1 | //===--- CodeGenAction.cpp - LLVM Code Generation Frontend Action ---------===// |
---|---|
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "clang/CodeGen/CodeGenAction.h" |
10 | #include "BackendConsumer.h" |
11 | #include "CGCall.h" |
12 | #include "CodeGenModule.h" |
13 | #include "CoverageMappingGen.h" |
14 | #include "MacroPPCallbacks.h" |
15 | #include "clang/AST/ASTConsumer.h" |
16 | #include "clang/AST/ASTContext.h" |
17 | #include "clang/AST/DeclCXX.h" |
18 | #include "clang/AST/DeclGroup.h" |
19 | #include "clang/Basic/DiagnosticFrontend.h" |
20 | #include "clang/Basic/FileManager.h" |
21 | #include "clang/Basic/LangStandard.h" |
22 | #include "clang/Basic/SourceManager.h" |
23 | #include "clang/Basic/TargetInfo.h" |
24 | #include "clang/CodeGen/BackendUtil.h" |
25 | #include "clang/CodeGen/ModuleBuilder.h" |
26 | #include "clang/Driver/DriverDiagnostic.h" |
27 | #include "clang/Frontend/CompilerInstance.h" |
28 | #include "clang/Frontend/MultiplexConsumer.h" |
29 | #include "clang/Lex/Preprocessor.h" |
30 | #include "clang/Serialization/ASTWriter.h" |
31 | #include "llvm/ADT/Hashing.h" |
32 | #include "llvm/Bitcode/BitcodeReader.h" |
33 | #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" |
34 | #include "llvm/Demangle/Demangle.h" |
35 | #include "llvm/IR/DebugInfo.h" |
36 | #include "llvm/IR/DiagnosticInfo.h" |
37 | #include "llvm/IR/DiagnosticPrinter.h" |
38 | #include "llvm/IR/GlobalValue.h" |
39 | #include "llvm/IR/LLVMContext.h" |
40 | #include "llvm/IR/LLVMRemarkStreamer.h" |
41 | #include "llvm/IR/Module.h" |
42 | #include "llvm/IR/Verifier.h" |
43 | #include "llvm/IRReader/IRReader.h" |
44 | #include "llvm/LTO/LTOBackend.h" |
45 | #include "llvm/Linker/Linker.h" |
46 | #include "llvm/Pass.h" |
47 | #include "llvm/Support/MemoryBuffer.h" |
48 | #include "llvm/Support/SourceMgr.h" |
49 | #include "llvm/Support/TimeProfiler.h" |
50 | #include "llvm/Support/Timer.h" |
51 | #include "llvm/Support/ToolOutputFile.h" |
52 | #include "llvm/Transforms/IPO/Internalize.h" |
53 | #include "llvm/Transforms/Utils/Cloning.h" |
54 | |
55 | #include <optional> |
56 | using namespace clang; |
57 | using namespace llvm; |
58 | |
59 | #define DEBUG_TYPE "codegenaction" |
60 | |
61 | namespace clang { |
62 | class BackendConsumer; |
63 | class ClangDiagnosticHandler final : public DiagnosticHandler { |
64 | public: |
65 | ClangDiagnosticHandler(const CodeGenOptions &CGOpts, BackendConsumer *BCon) |
66 | : CodeGenOpts(CGOpts), BackendCon(BCon) {} |
67 | |
68 | bool handleDiagnostics(const DiagnosticInfo &DI) override; |
69 | |
70 | bool isAnalysisRemarkEnabled(StringRef PassName) const override { |
71 | return CodeGenOpts.OptimizationRemarkAnalysis.patternMatches(String: PassName); |
72 | } |
73 | bool isMissedOptRemarkEnabled(StringRef PassName) const override { |
74 | return CodeGenOpts.OptimizationRemarkMissed.patternMatches(String: PassName); |
75 | } |
76 | bool isPassedOptRemarkEnabled(StringRef PassName) const override { |
77 | return CodeGenOpts.OptimizationRemark.patternMatches(String: PassName); |
78 | } |
79 | |
80 | bool isAnyRemarkEnabled() const override { |
81 | return CodeGenOpts.OptimizationRemarkAnalysis.hasValidPattern() || |
82 | CodeGenOpts.OptimizationRemarkMissed.hasValidPattern() || |
83 | CodeGenOpts.OptimizationRemark.hasValidPattern(); |
84 | } |
85 | |
86 | private: |
87 | const CodeGenOptions &CodeGenOpts; |
88 | BackendConsumer *BackendCon; |
89 | }; |
90 | |
91 | static void reportOptRecordError(Error E, DiagnosticsEngine &Diags, |
92 | const CodeGenOptions &CodeGenOpts) { |
93 | handleAllErrors( |
94 | E: std::move(E), |
95 | Handlers: [&](const LLVMRemarkSetupFileError &E) { |
96 | Diags.Report(diag::err_cannot_open_file) |
97 | << CodeGenOpts.OptRecordFile << E.message(); |
98 | }, |
99 | Handlers: [&](const LLVMRemarkSetupPatternError &E) { |
100 | Diags.Report(diag::err_drv_optimization_remark_pattern) |
101 | << E.message() << CodeGenOpts.OptRecordPasses; |
102 | }, |
103 | Handlers: [&](const LLVMRemarkSetupFormatError &E) { |
104 | Diags.Report(diag::err_drv_optimization_remark_format) |
105 | << CodeGenOpts.OptRecordFormat; |
106 | }); |
107 | } |
108 | |
109 | BackendConsumer::BackendConsumer(CompilerInstance &CI, BackendAction Action, |
110 | IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, |
111 | LLVMContext &C, |
112 | SmallVector<LinkModule, 4> LinkModules, |
113 | StringRef InFile, |
114 | std::unique_ptr<raw_pwrite_stream> OS, |
115 | CoverageSourceInfo *CoverageInfo, |
116 | llvm::Module *CurLinkModule) |
117 | : CI(CI), Diags(CI.getDiagnostics()), CodeGenOpts(CI.getCodeGenOpts()), |
118 | TargetOpts(CI.getTargetOpts()), LangOpts(CI.getLangOpts()), |
119 | AsmOutStream(std::move(OS)), FS(VFS), Action(Action), |
120 | Gen(CreateLLVMCodeGen(Diags, ModuleName: InFile, FS: std::move(VFS), |
121 | HeaderSearchOpts: CI.getHeaderSearchOpts(), PreprocessorOpts: CI.getPreprocessorOpts(), |
122 | CGO: CI.getCodeGenOpts(), C, CoverageInfo)), |
123 | LinkModules(std::move(LinkModules)), CurLinkModule(CurLinkModule) { |
124 | TimerIsEnabled = CodeGenOpts.TimePasses; |
125 | llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses; |
126 | llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun; |
127 | if (CodeGenOpts.TimePasses) |
128 | LLVMIRGeneration.init(TimerName: "irgen", TimerDescription: "LLVM IR generation", tg&: CI.getTimerGroup()); |
129 | } |
130 | |
131 | llvm::Module* BackendConsumer::getModule() const { |
132 | return Gen->GetModule(); |
133 | } |
134 | |
135 | std::unique_ptr<llvm::Module> BackendConsumer::takeModule() { |
136 | return std::unique_ptr<llvm::Module>(Gen->ReleaseModule()); |
137 | } |
138 | |
139 | CodeGenerator* BackendConsumer::getCodeGenerator() { |
140 | return Gen.get(); |
141 | } |
142 | |
143 | void BackendConsumer::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) { |
144 | Gen->HandleCXXStaticMemberVarInstantiation(D: VD); |
145 | } |
146 | |
147 | void BackendConsumer::Initialize(ASTContext &Ctx) { |
148 | assert(!Context && "initialized multiple times"); |
149 | |
150 | Context = &Ctx; |
151 | |
152 | if (TimerIsEnabled) |
153 | LLVMIRGeneration.startTimer(); |
154 | |
155 | Gen->Initialize(Context&: Ctx); |
156 | |
157 | if (TimerIsEnabled) |
158 | LLVMIRGeneration.stopTimer(); |
159 | } |
160 | |
161 | bool BackendConsumer::HandleTopLevelDecl(DeclGroupRef D) { |
162 | PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(), |
163 | Context->getSourceManager(), |
164 | "LLVM IR generation of declaration"); |
165 | |
166 | // Recurse. |
167 | if (TimerIsEnabled && !LLVMIRGenerationRefCount++) |
168 | CI.getFrontendTimer().yieldTo(LLVMIRGeneration); |
169 | |
170 | Gen->HandleTopLevelDecl(D); |
171 | |
172 | if (TimerIsEnabled && !--LLVMIRGenerationRefCount) |
173 | LLVMIRGeneration.yieldTo(CI.getFrontendTimer()); |
174 | |
175 | return true; |
176 | } |
177 | |
178 | void BackendConsumer::HandleInlineFunctionDefinition(FunctionDecl *D) { |
179 | PrettyStackTraceDecl CrashInfo(D, SourceLocation(), |
180 | Context->getSourceManager(), |
181 | "LLVM IR generation of inline function"); |
182 | if (TimerIsEnabled) |
183 | CI.getFrontendTimer().yieldTo(LLVMIRGeneration); |
184 | |
185 | Gen->HandleInlineFunctionDefinition(D); |
186 | |
187 | if (TimerIsEnabled) |
188 | LLVMIRGeneration.yieldTo(CI.getFrontendTimer()); |
189 | } |
190 | |
191 | void BackendConsumer::HandleInterestingDecl(DeclGroupRef D) { |
192 | // Ignore interesting decls from the AST reader after IRGen is finished. |
193 | if (!IRGenFinished) |
194 | HandleTopLevelDecl(D); |
195 | } |
196 | |
197 | // Links each entry in LinkModules into our module. Returns true on error. |
198 | bool BackendConsumer::LinkInModules(llvm::Module *M) { |
199 | for (auto &LM : LinkModules) { |
200 | assert(LM.Module && "LinkModule does not actually have a module"); |
201 | |
202 | if (LM.PropagateAttrs) |
203 | for (Function &F : *LM.Module) { |
204 | // Skip intrinsics. Keep consistent with how intrinsics are created |
205 | // in LLVM IR. |
206 | if (F.isIntrinsic()) |
207 | continue; |
208 | CodeGen::mergeDefaultFunctionDefinitionAttributes( |
209 | F, CodeGenOpts, LangOpts, TargetOpts, WillInternalize: LM.Internalize); |
210 | } |
211 | |
212 | CurLinkModule = LM.Module.get(); |
213 | bool Err; |
214 | |
215 | if (LM.Internalize) { |
216 | Err = Linker::linkModules( |
217 | Dest&: *M, Src: std::move(LM.Module), Flags: LM.LinkFlags, |
218 | InternalizeCallback: [](llvm::Module &M, const llvm::StringSet<> &GVS) { |
219 | internalizeModule(TheModule&: M, MustPreserveGV: [&GVS](const llvm::GlobalValue &GV) { |
220 | return !GV.hasName() || (GVS.count(Key: GV.getName()) == 0); |
221 | }); |
222 | }); |
223 | } else |
224 | Err = Linker::linkModules(Dest&: *M, Src: std::move(LM.Module), Flags: LM.LinkFlags); |
225 | |
226 | if (Err) |
227 | return true; |
228 | } |
229 | |
230 | LinkModules.clear(); |
231 | return false; // success |
232 | } |
233 | |
234 | void BackendConsumer::HandleTranslationUnit(ASTContext &C) { |
235 | { |
236 | llvm::TimeTraceScope TimeScope("Frontend"); |
237 | PrettyStackTraceString CrashInfo("Per-file LLVM IR generation"); |
238 | if (TimerIsEnabled && !LLVMIRGenerationRefCount++) |
239 | CI.getFrontendTimer().yieldTo(LLVMIRGeneration); |
240 | |
241 | Gen->HandleTranslationUnit(Ctx&: C); |
242 | |
243 | if (TimerIsEnabled && !--LLVMIRGenerationRefCount) |
244 | LLVMIRGeneration.yieldTo(CI.getFrontendTimer()); |
245 | |
246 | IRGenFinished = true; |
247 | } |
248 | |
249 | // Silently ignore if we weren't initialized for some reason. |
250 | if (!getModule()) |
251 | return; |
252 | |
253 | LLVMContext &Ctx = getModule()->getContext(); |
254 | std::unique_ptr<DiagnosticHandler> OldDiagnosticHandler = |
255 | Ctx.getDiagnosticHandler(); |
256 | Ctx.setDiagnosticHandler(DH: std::make_unique<ClangDiagnosticHandler>( |
257 | args: CodeGenOpts, args: this)); |
258 | |
259 | Ctx.setDefaultTargetCPU(TargetOpts.CPU); |
260 | Ctx.setDefaultTargetFeatures(llvm::join(R: TargetOpts.Features, Separator: ",")); |
261 | |
262 | Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr = |
263 | setupLLVMOptimizationRemarks( |
264 | Context&: Ctx, RemarksFilename: CodeGenOpts.OptRecordFile, RemarksPasses: CodeGenOpts.OptRecordPasses, |
265 | RemarksFormat: CodeGenOpts.OptRecordFormat, RemarksWithHotness: CodeGenOpts.DiagnosticsWithHotness, |
266 | RemarksHotnessThreshold: CodeGenOpts.DiagnosticsHotnessThreshold); |
267 | |
268 | if (Error E = OptRecordFileOrErr.takeError()) { |
269 | reportOptRecordError(E: std::move(E), Diags, CodeGenOpts); |
270 | return; |
271 | } |
272 | |
273 | std::unique_ptr<llvm::ToolOutputFile> OptRecordFile = |
274 | std::move(*OptRecordFileOrErr); |
275 | |
276 | if (OptRecordFile && |
277 | CodeGenOpts.getProfileUse() != CodeGenOptions::ProfileNone) |
278 | Ctx.setDiagnosticsHotnessRequested(true); |
279 | |
280 | if (CodeGenOpts.MisExpect) { |
281 | Ctx.setMisExpectWarningRequested(true); |
282 | } |
283 | |
284 | if (CodeGenOpts.DiagnosticsMisExpectTolerance) { |
285 | Ctx.setDiagnosticsMisExpectTolerance( |
286 | CodeGenOpts.DiagnosticsMisExpectTolerance); |
287 | } |
288 | |
289 | // Link each LinkModule into our module. |
290 | if (!CodeGenOpts.LinkBitcodePostopt && LinkInModules(M: getModule())) |
291 | return; |
292 | |
293 | for (auto &F : getModule()->functions()) { |
294 | if (const Decl *FD = Gen->GetDeclForMangledName(MangledName: F.getName())) { |
295 | auto Loc = FD->getASTContext().getFullLoc(Loc: FD->getLocation()); |
296 | // TODO: use a fast content hash when available. |
297 | auto NameHash = llvm::hash_value(S: F.getName()); |
298 | ManglingFullSourceLocs.push_back(x: std::make_pair(x&: NameHash, y&: Loc)); |
299 | } |
300 | } |
301 | |
302 | if (CodeGenOpts.ClearASTBeforeBackend) { |
303 | LLVM_DEBUG(llvm::dbgs() << "Clearing AST...\n"); |
304 | // Access to the AST is no longer available after this. |
305 | // Other things that the ASTContext manages are still available, e.g. |
306 | // the SourceManager. It'd be nice if we could separate out all the |
307 | // things in ASTContext used after this point and null out the |
308 | // ASTContext, but too many various parts of the ASTContext are still |
309 | // used in various parts. |
310 | C.cleanup(); |
311 | C.getAllocator().Reset(); |
312 | } |
313 | |
314 | EmbedBitcode(M: getModule(), CGOpts: CodeGenOpts, Buf: llvm::MemoryBufferRef()); |
315 | |
316 | emitBackendOutput(CI, CGOpts&: CI.getCodeGenOpts(), |
317 | TDesc: C.getTargetInfo().getDataLayoutString(), M: getModule(), |
318 | Action, VFS: FS, OS: std::move(AsmOutStream), BC: this); |
319 | |
320 | Ctx.setDiagnosticHandler(DH: std::move(OldDiagnosticHandler)); |
321 | |
322 | if (OptRecordFile) |
323 | OptRecordFile->keep(); |
324 | } |
325 | |
326 | void BackendConsumer::HandleTagDeclDefinition(TagDecl *D) { |
327 | PrettyStackTraceDecl CrashInfo(D, SourceLocation(), |
328 | Context->getSourceManager(), |
329 | "LLVM IR generation of declaration"); |
330 | Gen->HandleTagDeclDefinition(D); |
331 | } |
332 | |
333 | void BackendConsumer::HandleTagDeclRequiredDefinition(const TagDecl *D) { |
334 | Gen->HandleTagDeclRequiredDefinition(D); |
335 | } |
336 | |
337 | void BackendConsumer::CompleteTentativeDefinition(VarDecl *D) { |
338 | Gen->CompleteTentativeDefinition(D); |
339 | } |
340 | |
341 | void BackendConsumer::CompleteExternalDeclaration(DeclaratorDecl *D) { |
342 | Gen->CompleteExternalDeclaration(D); |
343 | } |
344 | |
345 | void BackendConsumer::AssignInheritanceModel(CXXRecordDecl *RD) { |
346 | Gen->AssignInheritanceModel(RD); |
347 | } |
348 | |
349 | void BackendConsumer::HandleVTable(CXXRecordDecl *RD) { |
350 | Gen->HandleVTable(RD); |
351 | } |
352 | |
353 | void BackendConsumer::anchor() { } |
354 | |
355 | } // namespace clang |
356 | |
357 | bool ClangDiagnosticHandler::handleDiagnostics(const DiagnosticInfo &DI) { |
358 | BackendCon->DiagnosticHandlerImpl(DI); |
359 | return true; |
360 | } |
361 | |
362 | /// ConvertBackendLocation - Convert a location in a temporary llvm::SourceMgr |
363 | /// buffer to be a valid FullSourceLoc. |
364 | static FullSourceLoc ConvertBackendLocation(const llvm::SMDiagnostic &D, |
365 | SourceManager &CSM) { |
366 | // Get both the clang and llvm source managers. The location is relative to |
367 | // a memory buffer that the LLVM Source Manager is handling, we need to add |
368 | // a copy to the Clang source manager. |
369 | const llvm::SourceMgr &LSM = *D.getSourceMgr(); |
370 | |
371 | // We need to copy the underlying LLVM memory buffer because llvm::SourceMgr |
372 | // already owns its one and clang::SourceManager wants to own its one. |
373 | const MemoryBuffer *LBuf = |
374 | LSM.getMemoryBuffer(i: LSM.FindBufferContainingLoc(Loc: D.getLoc())); |
375 | |
376 | // Create the copy and transfer ownership to clang::SourceManager. |
377 | // TODO: Avoid copying files into memory. |
378 | std::unique_ptr<llvm::MemoryBuffer> CBuf = |
379 | llvm::MemoryBuffer::getMemBufferCopy(InputData: LBuf->getBuffer(), |
380 | BufferName: LBuf->getBufferIdentifier()); |
381 | // FIXME: Keep a file ID map instead of creating new IDs for each location. |
382 | FileID FID = CSM.createFileID(Buffer: std::move(CBuf)); |
383 | |
384 | // Translate the offset into the file. |
385 | unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart(); |
386 | SourceLocation NewLoc = |
387 | CSM.getLocForStartOfFile(FID).getLocWithOffset(Offset); |
388 | return FullSourceLoc(NewLoc, CSM); |
389 | } |
390 | |
391 | #define ComputeDiagID(Severity, GroupName, DiagID) \ |
392 | do { \ |
393 | switch (Severity) { \ |
394 | case llvm::DS_Error: \ |
395 | DiagID = diag::err_fe_##GroupName; \ |
396 | break; \ |
397 | case llvm::DS_Warning: \ |
398 | DiagID = diag::warn_fe_##GroupName; \ |
399 | break; \ |
400 | case llvm::DS_Remark: \ |
401 | llvm_unreachable("'remark' severity not expected"); \ |
402 | break; \ |
403 | case llvm::DS_Note: \ |
404 | DiagID = diag::note_fe_##GroupName; \ |
405 | break; \ |
406 | } \ |
407 | } while (false) |
408 | |
409 | #define ComputeDiagRemarkID(Severity, GroupName, DiagID) \ |
410 | do { \ |
411 | switch (Severity) { \ |
412 | case llvm::DS_Error: \ |
413 | DiagID = diag::err_fe_##GroupName; \ |
414 | break; \ |
415 | case llvm::DS_Warning: \ |
416 | DiagID = diag::warn_fe_##GroupName; \ |
417 | break; \ |
418 | case llvm::DS_Remark: \ |
419 | DiagID = diag::remark_fe_##GroupName; \ |
420 | break; \ |
421 | case llvm::DS_Note: \ |
422 | DiagID = diag::note_fe_##GroupName; \ |
423 | break; \ |
424 | } \ |
425 | } while (false) |
426 | |
427 | void BackendConsumer::SrcMgrDiagHandler(const llvm::DiagnosticInfoSrcMgr &DI) { |
428 | const llvm::SMDiagnostic &D = DI.getSMDiag(); |
429 | |
430 | unsigned DiagID; |
431 | if (DI.isInlineAsmDiag()) |
432 | ComputeDiagID(DI.getSeverity(), inline_asm, DiagID); |
433 | else |
434 | ComputeDiagID(DI.getSeverity(), source_mgr, DiagID); |
435 | |
436 | // This is for the empty BackendConsumer that uses the clang diagnostic |
437 | // handler for IR input files. |
438 | if (!Context) { |
439 | D.print(ProgName: nullptr, S&: llvm::errs()); |
440 | Diags.Report(DiagID).AddString(V: "cannot compile inline asm"); |
441 | return; |
442 | } |
443 | |
444 | // There are a couple of different kinds of errors we could get here. |
445 | // First, we re-format the SMDiagnostic in terms of a clang diagnostic. |
446 | |
447 | // Strip "error: " off the start of the message string. |
448 | StringRef Message = D.getMessage(); |
449 | (void)Message.consume_front(Prefix: "error: "); |
450 | |
451 | // If the SMDiagnostic has an inline asm source location, translate it. |
452 | FullSourceLoc Loc; |
453 | if (D.getLoc() != SMLoc()) |
454 | Loc = ConvertBackendLocation(D, CSM&: Context->getSourceManager()); |
455 | |
456 | // If this problem has clang-level source location information, report the |
457 | // issue in the source with a note showing the instantiated |
458 | // code. |
459 | if (DI.isInlineAsmDiag()) { |
460 | SourceLocation LocCookie = |
461 | SourceLocation::getFromRawEncoding(Encoding: DI.getLocCookie()); |
462 | if (LocCookie.isValid()) { |
463 | Diags.Report(Loc: LocCookie, DiagID).AddString(V: Message); |
464 | |
465 | if (D.getLoc().isValid()) { |
466 | DiagnosticBuilder B = Diags.Report(Loc, diag::note_fe_inline_asm_here); |
467 | // Convert the SMDiagnostic ranges into SourceRange and attach them |
468 | // to the diagnostic. |
469 | for (const std::pair<unsigned, unsigned> &Range : D.getRanges()) { |
470 | unsigned Column = D.getColumnNo(); |
471 | B << SourceRange(Loc.getLocWithOffset(Offset: Range.first - Column), |
472 | Loc.getLocWithOffset(Offset: Range.second - Column)); |
473 | } |
474 | } |
475 | return; |
476 | } |
477 | } |
478 | |
479 | // Otherwise, report the backend issue as occurring in the generated .s file. |
480 | // If Loc is invalid, we still need to report the issue, it just gets no |
481 | // location info. |
482 | Diags.Report(Loc, DiagID).AddString(V: Message); |
483 | } |
484 | |
485 | bool |
486 | BackendConsumer::InlineAsmDiagHandler(const llvm::DiagnosticInfoInlineAsm &D) { |
487 | unsigned DiagID; |
488 | ComputeDiagID(D.getSeverity(), inline_asm, DiagID); |
489 | std::string Message = D.getMsgStr().str(); |
490 | |
491 | // If this problem has clang-level source location information, report the |
492 | // issue as being a problem in the source with a note showing the instantiated |
493 | // code. |
494 | SourceLocation LocCookie = |
495 | SourceLocation::getFromRawEncoding(Encoding: D.getLocCookie()); |
496 | if (LocCookie.isValid()) |
497 | Diags.Report(Loc: LocCookie, DiagID).AddString(V: Message); |
498 | else { |
499 | // Otherwise, report the backend diagnostic as occurring in the generated |
500 | // .s file. |
501 | // If Loc is invalid, we still need to report the diagnostic, it just gets |
502 | // no location info. |
503 | FullSourceLoc Loc; |
504 | Diags.Report(Loc, DiagID).AddString(V: Message); |
505 | } |
506 | // We handled all the possible severities. |
507 | return true; |
508 | } |
509 | |
510 | bool |
511 | BackendConsumer::StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D) { |
512 | if (D.getSeverity() != llvm::DS_Warning) |
513 | // For now, the only support we have for StackSize diagnostic is warning. |
514 | // We do not know how to format other severities. |
515 | return false; |
516 | |
517 | auto Loc = getFunctionSourceLocation(F: D.getFunction()); |
518 | if (!Loc) |
519 | return false; |
520 | |
521 | Diags.Report(*Loc, diag::warn_fe_frame_larger_than) |
522 | << D.getStackSize() << D.getStackLimit() |
523 | << llvm::demangle(D.getFunction().getName()); |
524 | return true; |
525 | } |
526 | |
527 | bool BackendConsumer::ResourceLimitDiagHandler( |
528 | const llvm::DiagnosticInfoResourceLimit &D) { |
529 | auto Loc = getFunctionSourceLocation(F: D.getFunction()); |
530 | if (!Loc) |
531 | return false; |
532 | unsigned DiagID = diag::err_fe_backend_resource_limit; |
533 | ComputeDiagID(D.getSeverity(), backend_resource_limit, DiagID); |
534 | |
535 | Diags.Report(Loc: *Loc, DiagID) |
536 | << D.getResourceName() << D.getResourceSize() << D.getResourceLimit() |
537 | << llvm::demangle(MangledName: D.getFunction().getName()); |
538 | return true; |
539 | } |
540 | |
541 | const FullSourceLoc BackendConsumer::getBestLocationFromDebugLoc( |
542 | const llvm::DiagnosticInfoWithLocationBase &D, bool &BadDebugInfo, |
543 | StringRef &Filename, unsigned &Line, unsigned &Column) const { |
544 | SourceManager &SourceMgr = Context->getSourceManager(); |
545 | FileManager &FileMgr = SourceMgr.getFileManager(); |
546 | SourceLocation DILoc; |
547 | |
548 | if (D.isLocationAvailable()) { |
549 | D.getLocation(RelativePath&: Filename, Line, Column); |
550 | if (Line > 0) { |
551 | auto FE = FileMgr.getOptionalFileRef(Filename); |
552 | if (!FE) |
553 | FE = FileMgr.getOptionalFileRef(Filename: D.getAbsolutePath()); |
554 | if (FE) { |
555 | // If -gcolumn-info was not used, Column will be 0. This upsets the |
556 | // source manager, so pass 1 if Column is not set. |
557 | DILoc = SourceMgr.translateFileLineCol(SourceFile: *FE, Line, Col: Column ? Column : 1); |
558 | } |
559 | } |
560 | BadDebugInfo = DILoc.isInvalid(); |
561 | } |
562 | |
563 | // If a location isn't available, try to approximate it using the associated |
564 | // function definition. We use the definition's right brace to differentiate |
565 | // from diagnostics that genuinely relate to the function itself. |
566 | FullSourceLoc Loc(DILoc, SourceMgr); |
567 | if (Loc.isInvalid()) { |
568 | if (auto MaybeLoc = getFunctionSourceLocation(F: D.getFunction())) |
569 | Loc = *MaybeLoc; |
570 | } |
571 | |
572 | if (DILoc.isInvalid() && D.isLocationAvailable()) |
573 | // If we were not able to translate the file:line:col information |
574 | // back to a SourceLocation, at least emit a note stating that |
575 | // we could not translate this location. This can happen in the |
576 | // case of #line directives. |
577 | Diags.Report(Loc, diag::note_fe_backend_invalid_loc) |
578 | << Filename << Line << Column; |
579 | |
580 | return Loc; |
581 | } |
582 | |
583 | std::optional<FullSourceLoc> |
584 | BackendConsumer::getFunctionSourceLocation(const Function &F) const { |
585 | auto Hash = llvm::hash_value(S: F.getName()); |
586 | for (const auto &Pair : ManglingFullSourceLocs) { |
587 | if (Pair.first == Hash) |
588 | return Pair.second; |
589 | } |
590 | return std::nullopt; |
591 | } |
592 | |
593 | void BackendConsumer::UnsupportedDiagHandler( |
594 | const llvm::DiagnosticInfoUnsupported &D) { |
595 | // We only support warnings or errors. |
596 | assert(D.getSeverity() == llvm::DS_Error || |
597 | D.getSeverity() == llvm::DS_Warning); |
598 | |
599 | StringRef Filename; |
600 | unsigned Line, Column; |
601 | bool BadDebugInfo = false; |
602 | FullSourceLoc Loc; |
603 | std::string Msg; |
604 | raw_string_ostream MsgStream(Msg); |
605 | |
606 | // Context will be nullptr for IR input files, we will construct the diag |
607 | // message from llvm::DiagnosticInfoUnsupported. |
608 | if (Context != nullptr) { |
609 | Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column); |
610 | MsgStream << D.getMessage(); |
611 | } else { |
612 | DiagnosticPrinterRawOStream DP(MsgStream); |
613 | D.print(DP); |
614 | } |
615 | |
616 | auto DiagType = D.getSeverity() == llvm::DS_Error |
617 | ? diag::err_fe_backend_unsupported |
618 | : diag::warn_fe_backend_unsupported; |
619 | Diags.Report(Loc, DiagType) << Msg; |
620 | |
621 | if (BadDebugInfo) |
622 | // If we were not able to translate the file:line:col information |
623 | // back to a SourceLocation, at least emit a note stating that |
624 | // we could not translate this location. This can happen in the |
625 | // case of #line directives. |
626 | Diags.Report(Loc, diag::note_fe_backend_invalid_loc) |
627 | << Filename << Line << Column; |
628 | } |
629 | |
630 | void BackendConsumer::EmitOptimizationMessage( |
631 | const llvm::DiagnosticInfoOptimizationBase &D, unsigned DiagID) { |
632 | // We only support warnings and remarks. |
633 | assert(D.getSeverity() == llvm::DS_Remark || |
634 | D.getSeverity() == llvm::DS_Warning); |
635 | |
636 | StringRef Filename; |
637 | unsigned Line, Column; |
638 | bool BadDebugInfo = false; |
639 | FullSourceLoc Loc; |
640 | std::string Msg; |
641 | raw_string_ostream MsgStream(Msg); |
642 | |
643 | // Context will be nullptr for IR input files, we will construct the remark |
644 | // message from llvm::DiagnosticInfoOptimizationBase. |
645 | if (Context != nullptr) { |
646 | Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column); |
647 | MsgStream << D.getMsg(); |
648 | } else { |
649 | DiagnosticPrinterRawOStream DP(MsgStream); |
650 | D.print(DP); |
651 | } |
652 | |
653 | if (D.getHotness()) |
654 | MsgStream << " (hotness: "<< *D.getHotness() << ")"; |
655 | |
656 | Diags.Report(Loc, DiagID) << AddFlagValue(D.getPassName()) << Msg; |
657 | |
658 | if (BadDebugInfo) |
659 | // If we were not able to translate the file:line:col information |
660 | // back to a SourceLocation, at least emit a note stating that |
661 | // we could not translate this location. This can happen in the |
662 | // case of #line directives. |
663 | Diags.Report(Loc, diag::note_fe_backend_invalid_loc) |
664 | << Filename << Line << Column; |
665 | } |
666 | |
667 | void BackendConsumer::OptimizationRemarkHandler( |
668 | const llvm::DiagnosticInfoOptimizationBase &D) { |
669 | // Without hotness information, don't show noisy remarks. |
670 | if (D.isVerbose() && !D.getHotness()) |
671 | return; |
672 | |
673 | if (D.isPassed()) { |
674 | // Optimization remarks are active only if the -Rpass flag has a regular |
675 | // expression that matches the name of the pass name in \p D. |
676 | if (CodeGenOpts.OptimizationRemark.patternMatches(D.getPassName())) |
677 | EmitOptimizationMessage(D, diag::remark_fe_backend_optimization_remark); |
678 | } else if (D.isMissed()) { |
679 | // Missed optimization remarks are active only if the -Rpass-missed |
680 | // flag has a regular expression that matches the name of the pass |
681 | // name in \p D. |
682 | if (CodeGenOpts.OptimizationRemarkMissed.patternMatches(D.getPassName())) |
683 | EmitOptimizationMessage( |
684 | D, diag::remark_fe_backend_optimization_remark_missed); |
685 | } else { |
686 | assert(D.isAnalysis() && "Unknown remark type"); |
687 | |
688 | bool ShouldAlwaysPrint = false; |
689 | if (auto *ORA = dyn_cast<llvm::OptimizationRemarkAnalysis>(Val: &D)) |
690 | ShouldAlwaysPrint = ORA->shouldAlwaysPrint(); |
691 | |
692 | if (ShouldAlwaysPrint || |
693 | CodeGenOpts.OptimizationRemarkAnalysis.patternMatches(D.getPassName())) |
694 | EmitOptimizationMessage( |
695 | D, diag::remark_fe_backend_optimization_remark_analysis); |
696 | } |
697 | } |
698 | |
699 | void BackendConsumer::OptimizationRemarkHandler( |
700 | const llvm::OptimizationRemarkAnalysisFPCommute &D) { |
701 | // Optimization analysis remarks are active if the pass name is set to |
702 | // llvm::DiagnosticInfo::AlwasyPrint or if the -Rpass-analysis flag has a |
703 | // regular expression that matches the name of the pass name in \p D. |
704 | |
705 | if (D.shouldAlwaysPrint() || |
706 | CodeGenOpts.OptimizationRemarkAnalysis.patternMatches(D.getPassName())) |
707 | EmitOptimizationMessage( |
708 | D, diag::remark_fe_backend_optimization_remark_analysis_fpcommute); |
709 | } |
710 | |
711 | void BackendConsumer::OptimizationRemarkHandler( |
712 | const llvm::OptimizationRemarkAnalysisAliasing &D) { |
713 | // Optimization analysis remarks are active if the pass name is set to |
714 | // llvm::DiagnosticInfo::AlwasyPrint or if the -Rpass-analysis flag has a |
715 | // regular expression that matches the name of the pass name in \p D. |
716 | |
717 | if (D.shouldAlwaysPrint() || |
718 | CodeGenOpts.OptimizationRemarkAnalysis.patternMatches(D.getPassName())) |
719 | EmitOptimizationMessage( |
720 | D, diag::remark_fe_backend_optimization_remark_analysis_aliasing); |
721 | } |
722 | |
723 | void BackendConsumer::OptimizationFailureHandler( |
724 | const llvm::DiagnosticInfoOptimizationFailure &D) { |
725 | EmitOptimizationMessage(D, diag::warn_fe_backend_optimization_failure); |
726 | } |
727 | |
728 | void BackendConsumer::DontCallDiagHandler(const DiagnosticInfoDontCall &D) { |
729 | SourceLocation LocCookie = |
730 | SourceLocation::getFromRawEncoding(Encoding: D.getLocCookie()); |
731 | |
732 | // FIXME: we can't yet diagnose indirect calls. When/if we can, we |
733 | // should instead assert that LocCookie.isValid(). |
734 | if (!LocCookie.isValid()) |
735 | return; |
736 | |
737 | Diags.Report(LocCookie, D.getSeverity() == DiagnosticSeverity::DS_Error |
738 | ? diag::err_fe_backend_error_attr |
739 | : diag::warn_fe_backend_warning_attr) |
740 | << llvm::demangle(D.getFunctionName()) << D.getNote(); |
741 | } |
742 | |
743 | void BackendConsumer::MisExpectDiagHandler( |
744 | const llvm::DiagnosticInfoMisExpect &D) { |
745 | StringRef Filename; |
746 | unsigned Line, Column; |
747 | bool BadDebugInfo = false; |
748 | FullSourceLoc Loc = |
749 | getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column); |
750 | |
751 | Diags.Report(Loc, diag::warn_profile_data_misexpect) << D.getMsg().str(); |
752 | |
753 | if (BadDebugInfo) |
754 | // If we were not able to translate the file:line:col information |
755 | // back to a SourceLocation, at least emit a note stating that |
756 | // we could not translate this location. This can happen in the |
757 | // case of #line directives. |
758 | Diags.Report(Loc, diag::note_fe_backend_invalid_loc) |
759 | << Filename << Line << Column; |
760 | } |
761 | |
762 | /// This function is invoked when the backend needs |
763 | /// to report something to the user. |
764 | void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) { |
765 | unsigned DiagID = diag::err_fe_inline_asm; |
766 | llvm::DiagnosticSeverity Severity = DI.getSeverity(); |
767 | // Get the diagnostic ID based. |
768 | switch (DI.getKind()) { |
769 | case llvm::DK_InlineAsm: |
770 | if (InlineAsmDiagHandler(D: cast<DiagnosticInfoInlineAsm>(Val: DI))) |
771 | return; |
772 | ComputeDiagID(Severity, inline_asm, DiagID); |
773 | break; |
774 | case llvm::DK_SrcMgr: |
775 | SrcMgrDiagHandler(DI: cast<DiagnosticInfoSrcMgr>(Val: DI)); |
776 | return; |
777 | case llvm::DK_StackSize: |
778 | if (StackSizeDiagHandler(D: cast<DiagnosticInfoStackSize>(Val: DI))) |
779 | return; |
780 | ComputeDiagID(Severity, backend_frame_larger_than, DiagID); |
781 | break; |
782 | case llvm::DK_ResourceLimit: |
783 | if (ResourceLimitDiagHandler(D: cast<DiagnosticInfoResourceLimit>(Val: DI))) |
784 | return; |
785 | ComputeDiagID(Severity, backend_resource_limit, DiagID); |
786 | break; |
787 | case DK_Linker: |
788 | ComputeDiagID(Severity, linking_module, DiagID); |
789 | break; |
790 | case llvm::DK_OptimizationRemark: |
791 | // Optimization remarks are always handled completely by this |
792 | // handler. There is no generic way of emitting them. |
793 | OptimizationRemarkHandler(D: cast<OptimizationRemark>(Val: DI)); |
794 | return; |
795 | case llvm::DK_OptimizationRemarkMissed: |
796 | // Optimization remarks are always handled completely by this |
797 | // handler. There is no generic way of emitting them. |
798 | OptimizationRemarkHandler(D: cast<OptimizationRemarkMissed>(Val: DI)); |
799 | return; |
800 | case llvm::DK_OptimizationRemarkAnalysis: |
801 | // Optimization remarks are always handled completely by this |
802 | // handler. There is no generic way of emitting them. |
803 | OptimizationRemarkHandler(D: cast<OptimizationRemarkAnalysis>(Val: DI)); |
804 | return; |
805 | case llvm::DK_OptimizationRemarkAnalysisFPCommute: |
806 | // Optimization remarks are always handled completely by this |
807 | // handler. There is no generic way of emitting them. |
808 | OptimizationRemarkHandler(D: cast<OptimizationRemarkAnalysisFPCommute>(Val: DI)); |
809 | return; |
810 | case llvm::DK_OptimizationRemarkAnalysisAliasing: |
811 | // Optimization remarks are always handled completely by this |
812 | // handler. There is no generic way of emitting them. |
813 | OptimizationRemarkHandler(D: cast<OptimizationRemarkAnalysisAliasing>(Val: DI)); |
814 | return; |
815 | case llvm::DK_MachineOptimizationRemark: |
816 | // Optimization remarks are always handled completely by this |
817 | // handler. There is no generic way of emitting them. |
818 | OptimizationRemarkHandler(D: cast<MachineOptimizationRemark>(Val: DI)); |
819 | return; |
820 | case llvm::DK_MachineOptimizationRemarkMissed: |
821 | // Optimization remarks are always handled completely by this |
822 | // handler. There is no generic way of emitting them. |
823 | OptimizationRemarkHandler(D: cast<MachineOptimizationRemarkMissed>(Val: DI)); |
824 | return; |
825 | case llvm::DK_MachineOptimizationRemarkAnalysis: |
826 | // Optimization remarks are always handled completely by this |
827 | // handler. There is no generic way of emitting them. |
828 | OptimizationRemarkHandler(D: cast<MachineOptimizationRemarkAnalysis>(Val: DI)); |
829 | return; |
830 | case llvm::DK_OptimizationFailure: |
831 | // Optimization failures are always handled completely by this |
832 | // handler. |
833 | OptimizationFailureHandler(D: cast<DiagnosticInfoOptimizationFailure>(Val: DI)); |
834 | return; |
835 | case llvm::DK_Unsupported: |
836 | UnsupportedDiagHandler(D: cast<DiagnosticInfoUnsupported>(Val: DI)); |
837 | return; |
838 | case llvm::DK_DontCall: |
839 | DontCallDiagHandler(D: cast<DiagnosticInfoDontCall>(Val: DI)); |
840 | return; |
841 | case llvm::DK_MisExpect: |
842 | MisExpectDiagHandler(D: cast<DiagnosticInfoMisExpect>(Val: DI)); |
843 | return; |
844 | default: |
845 | // Plugin IDs are not bound to any value as they are set dynamically. |
846 | ComputeDiagRemarkID(Severity, backend_plugin, DiagID); |
847 | break; |
848 | } |
849 | std::string MsgStorage; |
850 | { |
851 | raw_string_ostream Stream(MsgStorage); |
852 | DiagnosticPrinterRawOStream DP(Stream); |
853 | DI.print(DP); |
854 | } |
855 | |
856 | if (DI.getKind() == DK_Linker) { |
857 | assert(CurLinkModule && "CurLinkModule must be set for linker diagnostics"); |
858 | Diags.Report(DiagID) << CurLinkModule->getModuleIdentifier() << MsgStorage; |
859 | return; |
860 | } |
861 | |
862 | // Report the backend message using the usual diagnostic mechanism. |
863 | FullSourceLoc Loc; |
864 | Diags.Report(Loc, DiagID).AddString(V: MsgStorage); |
865 | } |
866 | #undef ComputeDiagID |
867 | |
868 | CodeGenAction::CodeGenAction(unsigned _Act, LLVMContext *_VMContext) |
869 | : Act(_Act), VMContext(_VMContext ? _VMContext : new LLVMContext), |
870 | OwnsVMContext(!_VMContext) {} |
871 | |
872 | CodeGenAction::~CodeGenAction() { |
873 | TheModule.reset(); |
874 | if (OwnsVMContext) |
875 | delete VMContext; |
876 | } |
877 | |
878 | bool CodeGenAction::loadLinkModules(CompilerInstance &CI) { |
879 | if (!LinkModules.empty()) |
880 | return false; |
881 | |
882 | for (const CodeGenOptions::BitcodeFileToLink &F : |
883 | CI.getCodeGenOpts().LinkBitcodeFiles) { |
884 | auto BCBuf = CI.getFileManager().getBufferForFile(Filename: F.Filename); |
885 | if (!BCBuf) { |
886 | CI.getDiagnostics().Report(diag::err_cannot_open_file) |
887 | << F.Filename << BCBuf.getError().message(); |
888 | LinkModules.clear(); |
889 | return true; |
890 | } |
891 | |
892 | Expected<std::unique_ptr<llvm::Module>> ModuleOrErr = |
893 | getOwningLazyBitcodeModule(Buffer: std::move(*BCBuf), Context&: *VMContext); |
894 | if (!ModuleOrErr) { |
895 | handleAllErrors(E: ModuleOrErr.takeError(), Handlers: [&](ErrorInfoBase &EIB) { |
896 | CI.getDiagnostics().Report(diag::err_cannot_open_file) |
897 | << F.Filename << EIB.message(); |
898 | }); |
899 | LinkModules.clear(); |
900 | return true; |
901 | } |
902 | LinkModules.push_back(Elt: {.Module: std::move(ModuleOrErr.get()), .PropagateAttrs: F.PropagateAttrs, |
903 | .Internalize: F.Internalize, .LinkFlags: F.LinkFlags}); |
904 | } |
905 | return false; |
906 | } |
907 | |
908 | bool CodeGenAction::hasIRSupport() const { return true; } |
909 | |
910 | void CodeGenAction::EndSourceFileAction() { |
911 | // If the consumer creation failed, do nothing. |
912 | if (!getCompilerInstance().hasASTConsumer()) |
913 | return; |
914 | |
915 | // Steal the module from the consumer. |
916 | TheModule = BEConsumer->takeModule(); |
917 | } |
918 | |
919 | std::unique_ptr<llvm::Module> CodeGenAction::takeModule() { |
920 | return std::move(TheModule); |
921 | } |
922 | |
923 | llvm::LLVMContext *CodeGenAction::takeLLVMContext() { |
924 | OwnsVMContext = false; |
925 | return VMContext; |
926 | } |
927 | |
928 | CodeGenerator *CodeGenAction::getCodeGenerator() const { |
929 | return BEConsumer->getCodeGenerator(); |
930 | } |
931 | |
932 | bool CodeGenAction::BeginSourceFileAction(CompilerInstance &CI) { |
933 | if (CI.getFrontendOpts().GenReducedBMI) |
934 | CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface); |
935 | return true; |
936 | } |
937 | |
938 | static std::unique_ptr<raw_pwrite_stream> |
939 | GetOutputStream(CompilerInstance &CI, StringRef InFile, BackendAction Action) { |
940 | switch (Action) { |
941 | case Backend_EmitAssembly: |
942 | return CI.createDefaultOutputFile(Binary: false, BaseInput: InFile, Extension: "s"); |
943 | case Backend_EmitLL: |
944 | return CI.createDefaultOutputFile(Binary: false, BaseInput: InFile, Extension: "ll"); |
945 | case Backend_EmitBC: |
946 | return CI.createDefaultOutputFile(Binary: true, BaseInput: InFile, Extension: "bc"); |
947 | case Backend_EmitNothing: |
948 | return nullptr; |
949 | case Backend_EmitMCNull: |
950 | return CI.createNullOutputFile(); |
951 | case Backend_EmitObj: |
952 | return CI.createDefaultOutputFile(Binary: true, BaseInput: InFile, Extension: "o"); |
953 | } |
954 | |
955 | llvm_unreachable("Invalid action!"); |
956 | } |
957 | |
958 | std::unique_ptr<ASTConsumer> |
959 | CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { |
960 | BackendAction BA = static_cast<BackendAction>(Act); |
961 | std::unique_ptr<raw_pwrite_stream> OS = CI.takeOutputStream(); |
962 | if (!OS) |
963 | OS = GetOutputStream(CI, InFile, Action: BA); |
964 | |
965 | if (BA != Backend_EmitNothing && !OS) |
966 | return nullptr; |
967 | |
968 | // Load bitcode modules to link with, if we need to. |
969 | if (loadLinkModules(CI)) |
970 | return nullptr; |
971 | |
972 | CoverageSourceInfo *CoverageInfo = nullptr; |
973 | // Add the preprocessor callback only when the coverage mapping is generated. |
974 | if (CI.getCodeGenOpts().CoverageMapping) |
975 | CoverageInfo = CodeGen::CoverageMappingModuleGen::setUpCoverageCallbacks( |
976 | CI.getPreprocessor()); |
977 | |
978 | std::unique_ptr<BackendConsumer> Result(new BackendConsumer( |
979 | CI, BA, &CI.getVirtualFileSystem(), *VMContext, std::move(LinkModules), |
980 | InFile, std::move(OS), CoverageInfo)); |
981 | BEConsumer = Result.get(); |
982 | |
983 | // Enable generating macro debug info only when debug info is not disabled and |
984 | // also macro debug info is enabled. |
985 | if (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo && |
986 | CI.getCodeGenOpts().MacroDebugInfo) { |
987 | std::unique_ptr<PPCallbacks> Callbacks = |
988 | std::make_unique<MacroPPCallbacks>(args: BEConsumer->getCodeGenerator(), |
989 | args&: CI.getPreprocessor()); |
990 | CI.getPreprocessor().addPPCallbacks(C: std::move(Callbacks)); |
991 | } |
992 | |
993 | if (CI.getFrontendOpts().GenReducedBMI && |
994 | !CI.getFrontendOpts().ModuleOutputPath.empty()) { |
995 | std::vector<std::unique_ptr<ASTConsumer>> Consumers(2); |
996 | Consumers[0] = std::make_unique<ReducedBMIGenerator>( |
997 | args&: CI.getPreprocessor(), args&: CI.getModuleCache(), |
998 | args&: CI.getFrontendOpts().ModuleOutputPath); |
999 | Consumers[1] = std::move(Result); |
1000 | return std::make_unique<MultiplexConsumer>(args: std::move(Consumers)); |
1001 | } |
1002 | |
1003 | return std::move(Result); |
1004 | } |
1005 | |
1006 | std::unique_ptr<llvm::Module> |
1007 | CodeGenAction::loadModule(MemoryBufferRef MBRef) { |
1008 | CompilerInstance &CI = getCompilerInstance(); |
1009 | SourceManager &SM = CI.getSourceManager(); |
1010 | |
1011 | auto DiagErrors = [&](Error E) -> std::unique_ptr<llvm::Module> { |
1012 | unsigned DiagID = |
1013 | CI.getDiagnostics().getCustomDiagID(L: DiagnosticsEngine::Error, FormatString: "%0"); |
1014 | handleAllErrors(E: std::move(E), Handlers: [&](ErrorInfoBase &EIB) { |
1015 | CI.getDiagnostics().Report(DiagID) << EIB.message(); |
1016 | }); |
1017 | return {}; |
1018 | }; |
1019 | |
1020 | // For ThinLTO backend invocations, ensure that the context |
1021 | // merges types based on ODR identifiers. We also need to read |
1022 | // the correct module out of a multi-module bitcode file. |
1023 | if (!CI.getCodeGenOpts().ThinLTOIndexFile.empty()) { |
1024 | VMContext->enableDebugTypeODRUniquing(); |
1025 | |
1026 | Expected<std::vector<BitcodeModule>> BMsOrErr = getBitcodeModuleList(Buffer: MBRef); |
1027 | if (!BMsOrErr) |
1028 | return DiagErrors(BMsOrErr.takeError()); |
1029 | BitcodeModule *Bm = llvm::lto::findThinLTOModule(BMs: *BMsOrErr); |
1030 | // We have nothing to do if the file contains no ThinLTO module. This is |
1031 | // possible if ThinLTO compilation was not able to split module. Content of |
1032 | // the file was already processed by indexing and will be passed to the |
1033 | // linker using merged object file. |
1034 | if (!Bm) { |
1035 | auto M = std::make_unique<llvm::Module>(args: "empty", args&: *VMContext); |
1036 | M->setTargetTriple(Triple(CI.getTargetOpts().Triple)); |
1037 | return M; |
1038 | } |
1039 | Expected<std::unique_ptr<llvm::Module>> MOrErr = |
1040 | Bm->parseModule(Context&: *VMContext); |
1041 | if (!MOrErr) |
1042 | return DiagErrors(MOrErr.takeError()); |
1043 | return std::move(*MOrErr); |
1044 | } |
1045 | |
1046 | // Load bitcode modules to link with, if we need to. |
1047 | if (loadLinkModules(CI)) |
1048 | return nullptr; |
1049 | |
1050 | // Handle textual IR and bitcode file with one single module. |
1051 | llvm::SMDiagnostic Err; |
1052 | if (std::unique_ptr<llvm::Module> M = parseIR(Buffer: MBRef, Err, Context&: *VMContext)) { |
1053 | // For LLVM IR files, always verify the input and report the error in a way |
1054 | // that does not ask people to report an issue for it. |
1055 | std::string VerifierErr; |
1056 | raw_string_ostream VerifierErrStream(VerifierErr); |
1057 | if (llvm::verifyModule(M: *M, OS: &VerifierErrStream)) { |
1058 | CI.getDiagnostics().Report(diag::err_invalid_llvm_ir) << VerifierErr; |
1059 | return {}; |
1060 | } |
1061 | return M; |
1062 | } |
1063 | |
1064 | // If MBRef is a bitcode with multiple modules (e.g., -fsplit-lto-unit |
1065 | // output), place the extra modules (actually only one, a regular LTO module) |
1066 | // into LinkModules as if we are using -mlink-bitcode-file. |
1067 | Expected<std::vector<BitcodeModule>> BMsOrErr = getBitcodeModuleList(Buffer: MBRef); |
1068 | if (BMsOrErr && BMsOrErr->size()) { |
1069 | std::unique_ptr<llvm::Module> FirstM; |
1070 | for (auto &BM : *BMsOrErr) { |
1071 | Expected<std::unique_ptr<llvm::Module>> MOrErr = |
1072 | BM.parseModule(Context&: *VMContext); |
1073 | if (!MOrErr) |
1074 | return DiagErrors(MOrErr.takeError()); |
1075 | if (FirstM) |
1076 | LinkModules.push_back(Elt: {.Module: std::move(*MOrErr), /*PropagateAttrs=*/false, |
1077 | /*Internalize=*/false, /*LinkFlags=*/{}}); |
1078 | else |
1079 | FirstM = std::move(*MOrErr); |
1080 | } |
1081 | if (FirstM) |
1082 | return FirstM; |
1083 | } |
1084 | // If BMsOrErr fails, consume the error and use the error message from |
1085 | // parseIR. |
1086 | consumeError(Err: BMsOrErr.takeError()); |
1087 | |
1088 | // Translate from the diagnostic info to the SourceManager location if |
1089 | // available. |
1090 | // TODO: Unify this with ConvertBackendLocation() |
1091 | SourceLocation Loc; |
1092 | if (Err.getLineNo() > 0) { |
1093 | assert(Err.getColumnNo() >= 0); |
1094 | Loc = SM.translateFileLineCol(SourceFile: SM.getFileEntryForID(FID: SM.getMainFileID()), |
1095 | Line: Err.getLineNo(), Col: Err.getColumnNo() + 1); |
1096 | } |
1097 | |
1098 | // Strip off a leading diagnostic code if there is one. |
1099 | StringRef Msg = Err.getMessage(); |
1100 | Msg.consume_front(Prefix: "error: "); |
1101 | |
1102 | unsigned DiagID = |
1103 | CI.getDiagnostics().getCustomDiagID(L: DiagnosticsEngine::Error, FormatString: "%0"); |
1104 | |
1105 | CI.getDiagnostics().Report(Loc, DiagID) << Msg; |
1106 | return {}; |
1107 | } |
1108 | |
1109 | void CodeGenAction::ExecuteAction() { |
1110 | if (getCurrentFileKind().getLanguage() != Language::LLVM_IR) { |
1111 | this->ASTFrontendAction::ExecuteAction(); |
1112 | return; |
1113 | } |
1114 | |
1115 | // If this is an IR file, we have to treat it specially. |
1116 | BackendAction BA = static_cast<BackendAction>(Act); |
1117 | CompilerInstance &CI = getCompilerInstance(); |
1118 | auto &CodeGenOpts = CI.getCodeGenOpts(); |
1119 | auto &Diagnostics = CI.getDiagnostics(); |
1120 | std::unique_ptr<raw_pwrite_stream> OS = |
1121 | GetOutputStream(CI, InFile: getCurrentFileOrBufferName(), Action: BA); |
1122 | if (BA != Backend_EmitNothing && !OS) |
1123 | return; |
1124 | |
1125 | SourceManager &SM = CI.getSourceManager(); |
1126 | FileID FID = SM.getMainFileID(); |
1127 | std::optional<MemoryBufferRef> MainFile = SM.getBufferOrNone(FID); |
1128 | if (!MainFile) |
1129 | return; |
1130 | |
1131 | TheModule = loadModule(MBRef: *MainFile); |
1132 | if (!TheModule) |
1133 | return; |
1134 | |
1135 | const TargetOptions &TargetOpts = CI.getTargetOpts(); |
1136 | if (TheModule->getTargetTriple().str() != TargetOpts.Triple) { |
1137 | Diagnostics.Report(SourceLocation(), diag::warn_fe_override_module) |
1138 | << TargetOpts.Triple; |
1139 | TheModule->setTargetTriple(Triple(TargetOpts.Triple)); |
1140 | } |
1141 | |
1142 | EmbedObject(M: TheModule.get(), CGOpts: CodeGenOpts, Diags&: Diagnostics); |
1143 | EmbedBitcode(M: TheModule.get(), CGOpts: CodeGenOpts, Buf: *MainFile); |
1144 | |
1145 | LLVMContext &Ctx = TheModule->getContext(); |
1146 | |
1147 | // Restore any diagnostic handler previously set before returning from this |
1148 | // function. |
1149 | struct RAII { |
1150 | LLVMContext &Ctx; |
1151 | std::unique_ptr<DiagnosticHandler> PrevHandler = Ctx.getDiagnosticHandler(); |
1152 | ~RAII() { Ctx.setDiagnosticHandler(DH: std::move(PrevHandler)); } |
1153 | } _{.Ctx: Ctx}; |
1154 | |
1155 | // Set clang diagnostic handler. To do this we need to create a fake |
1156 | // BackendConsumer. |
1157 | BackendConsumer Result(CI, BA, &CI.getVirtualFileSystem(), *VMContext, |
1158 | std::move(LinkModules), "", nullptr, nullptr, |
1159 | TheModule.get()); |
1160 | |
1161 | // Link in each pending link module. |
1162 | if (!CodeGenOpts.LinkBitcodePostopt && Result.LinkInModules(M: &*TheModule)) |
1163 | return; |
1164 | |
1165 | // PR44896: Force DiscardValueNames as false. DiscardValueNames cannot be |
1166 | // true here because the valued names are needed for reading textual IR. |
1167 | Ctx.setDiscardValueNames(false); |
1168 | Ctx.setDiagnosticHandler( |
1169 | DH: std::make_unique<ClangDiagnosticHandler>(args&: CodeGenOpts, args: &Result)); |
1170 | |
1171 | Ctx.setDefaultTargetCPU(TargetOpts.CPU); |
1172 | Ctx.setDefaultTargetFeatures(llvm::join(R: TargetOpts.Features, Separator: ",")); |
1173 | |
1174 | Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr = |
1175 | setupLLVMOptimizationRemarks( |
1176 | Context&: Ctx, RemarksFilename: CodeGenOpts.OptRecordFile, RemarksPasses: CodeGenOpts.OptRecordPasses, |
1177 | RemarksFormat: CodeGenOpts.OptRecordFormat, RemarksWithHotness: CodeGenOpts.DiagnosticsWithHotness, |
1178 | RemarksHotnessThreshold: CodeGenOpts.DiagnosticsHotnessThreshold); |
1179 | |
1180 | if (Error E = OptRecordFileOrErr.takeError()) { |
1181 | reportOptRecordError(E: std::move(E), Diags&: Diagnostics, CodeGenOpts); |
1182 | return; |
1183 | } |
1184 | std::unique_ptr<llvm::ToolOutputFile> OptRecordFile = |
1185 | std::move(*OptRecordFileOrErr); |
1186 | |
1187 | emitBackendOutput(CI, CGOpts&: CI.getCodeGenOpts(), |
1188 | TDesc: CI.getTarget().getDataLayoutString(), M: TheModule.get(), Action: BA, |
1189 | VFS: CI.getFileManager().getVirtualFileSystemPtr(), |
1190 | OS: std::move(OS)); |
1191 | if (OptRecordFile) |
1192 | OptRecordFile->keep(); |
1193 | } |
1194 | |
1195 | // |
1196 | |
1197 | void EmitAssemblyAction::anchor() { } |
1198 | EmitAssemblyAction::EmitAssemblyAction(llvm::LLVMContext *_VMContext) |
1199 | : CodeGenAction(Backend_EmitAssembly, _VMContext) {} |
1200 | |
1201 | void EmitBCAction::anchor() { } |
1202 | EmitBCAction::EmitBCAction(llvm::LLVMContext *_VMContext) |
1203 | : CodeGenAction(Backend_EmitBC, _VMContext) {} |
1204 | |
1205 | void EmitLLVMAction::anchor() { } |
1206 | EmitLLVMAction::EmitLLVMAction(llvm::LLVMContext *_VMContext) |
1207 | : CodeGenAction(Backend_EmitLL, _VMContext) {} |
1208 | |
1209 | void EmitLLVMOnlyAction::anchor() { } |
1210 | EmitLLVMOnlyAction::EmitLLVMOnlyAction(llvm::LLVMContext *_VMContext) |
1211 | : CodeGenAction(Backend_EmitNothing, _VMContext) {} |
1212 | |
1213 | void EmitCodeGenOnlyAction::anchor() { } |
1214 | EmitCodeGenOnlyAction::EmitCodeGenOnlyAction(llvm::LLVMContext *_VMContext) |
1215 | : CodeGenAction(Backend_EmitMCNull, _VMContext) {} |
1216 | |
1217 | void EmitObjAction::anchor() { } |
1218 | EmitObjAction::EmitObjAction(llvm::LLVMContext *_VMContext) |
1219 | : CodeGenAction(Backend_EmitObj, _VMContext) {} |
1220 |
Definitions
- ClangDiagnosticHandler
- ClangDiagnosticHandler
- isAnalysisRemarkEnabled
- isMissedOptRemarkEnabled
- isPassedOptRemarkEnabled
- isAnyRemarkEnabled
- reportOptRecordError
- BackendConsumer
- getModule
- takeModule
- getCodeGenerator
- HandleCXXStaticMemberVarInstantiation
- Initialize
- HandleTopLevelDecl
- HandleInlineFunctionDefinition
- HandleInterestingDecl
- LinkInModules
- HandleTranslationUnit
- HandleTagDeclDefinition
- HandleTagDeclRequiredDefinition
- CompleteTentativeDefinition
- CompleteExternalDeclaration
- AssignInheritanceModel
- HandleVTable
- anchor
- handleDiagnostics
- ConvertBackendLocation
- SrcMgrDiagHandler
- InlineAsmDiagHandler
- StackSizeDiagHandler
- ResourceLimitDiagHandler
- getBestLocationFromDebugLoc
- getFunctionSourceLocation
- UnsupportedDiagHandler
- EmitOptimizationMessage
- OptimizationRemarkHandler
- OptimizationRemarkHandler
- OptimizationRemarkHandler
- OptimizationFailureHandler
- DontCallDiagHandler
- MisExpectDiagHandler
- DiagnosticHandlerImpl
- CodeGenAction
- ~CodeGenAction
- loadLinkModules
- hasIRSupport
- EndSourceFileAction
- takeModule
- takeLLVMContext
- getCodeGenerator
- BeginSourceFileAction
- GetOutputStream
- CreateASTConsumer
- loadModule
- ExecuteAction
- anchor
- EmitAssemblyAction
- anchor
- EmitBCAction
- anchor
- EmitLLVMAction
- anchor
- EmitLLVMOnlyAction
- anchor
- EmitCodeGenOnlyAction
- anchor
Improve your Profiling and Debugging skills
Find out more