clang 24.0.0git
CIRGenAction.cpp
Go to the documentation of this file.
1//===--- CIRGenAction.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
11#include "mlir/IR/MLIRContext.h"
12#include "mlir/IR/OwningOpRef.h"
21#include "llvm/ADT/ScopeExit.h"
22#include "llvm/ADT/SmallString.h"
23#include "llvm/ADT/StringSet.h"
24#include "llvm/IR/DiagnosticHandler.h"
25#include "llvm/IR/Function.h"
26#include "llvm/IR/GlobalValue.h"
27#include "llvm/IR/LLVMContext.h"
28#include "llvm/IR/Module.h"
29#include "llvm/Linker/Linker.h"
30#include "llvm/Support/Path.h"
31#include "llvm/Support/raw_ostream.h"
32#include "llvm/Transforms/IPO/Internalize.h"
33
34using namespace cir;
35using namespace clang;
36
37namespace cir {
38
39static BackendAction
41 switch (Action) {
43 assert(false &&
44 "Unsupported output type for getBackendActionFromOutputType!");
45 break; // Unreachable, but fall through to report that
54 }
55 // We should only get here if a non-enum value is passed in or we went through
56 // the assert(false) case above
57 llvm_unreachable("Unsupported output type!");
58}
59
60static std::unique_ptr<llvm::Module>
61lowerFromCIRToLLVMIR(mlir::ModuleOp MLIRModule, llvm::LLVMContext &LLVMCtx,
62 bool EnableOpenMP,
63 llvm::StringRef mlirSaveTempsOutFile = {},
64 llvm::vfs::FileSystem *fs = nullptr) {
65 return direct::lowerDirectlyFromCIRToLLVMIR(MLIRModule, LLVMCtx, EnableOpenMP,
66 mlirSaveTempsOutFile, fs);
67}
68
70
71 virtual void anchor();
72
74
76
77 std::unique_ptr<raw_pwrite_stream> OutputStream;
78
79 ASTContext *Context{nullptr};
81 std::unique_ptr<CIRGenerator> Gen;
82 const FrontendOptions &FEOptions;
83 CodeGenOptions &CGO;
84
85 llvm::LLVMContext &LLVMCtx;
87
88 std::optional<CIRDiagnosticHandler> MLIRDiagHandler;
89
90public:
92 CodeGenOptions &CGO, std::unique_ptr<raw_pwrite_stream> OS,
93 llvm::LLVMContext &LLVMCtx,
95 : Action(Action), CI(CI), OutputStream(std::move(OS)),
96 FS(&CI.getVirtualFileSystem()),
97 Gen(std::make_unique<CIRGenerator>(CI.getDiagnostics(), std::move(FS),
98 CI.getCodeGenOpts())),
99 FEOptions(CI.getFrontendOpts()), CGO(CGO), LLVMCtx(LLVMCtx),
100 LinkModules(LinkModules) {}
101
102 void Initialize(ASTContext &Ctx) override {
103 assert(!Context && "initialized multiple times");
104 Context = &Ctx;
105 Gen->Initialize(Ctx);
106 // Install the MLIR diagnostic handler now that CIRGenerator owns its
107 // MLIRContext. Lifetime is tied to this consumer, which spans CIRGen,
108 // CIR-to-CIR passes, and CIR-to-LLVM lowering.
109 MLIRDiagHandler.emplace(&Gen->getMLIRContext(), CI.getDiagnostics(),
110 CI.getSourceManager(), CI.getFileManager());
111 }
112
114 Gen->HandleTopLevelDecl(D);
115 return true;
116 }
117
119 Gen->HandleCXXStaticMemberVarInstantiation(VD);
120 }
121
123 const OpenACCRoutineDecl *RD) override {
124 Gen->HandleOpenACCRoutineReference(FD, RD);
125 }
126
128 Gen->HandleInlineFunctionDefinition(D);
129 }
130
132 Gen->HandleTranslationUnit(C);
133
134 if (!FEOptions.ClangIRDisableCIRVerifier) {
135 if (!Gen->verifyModule()) {
136 // Verifier output already routed through ClangIRDiagnosticHandler.
137 // Only emit the generic fatal if nothing more specific was reported.
138 if (!CI.getDiagnostics().hasErrorOccurred())
139 CI.getDiagnostics().Report(
140 diag::err_cir_verification_failed_pre_passes);
141 llvm::report_fatal_error(
142 "CIR codegen: module verification error before running CIR passes");
143 return;
144 }
145 }
146
147 mlir::ModuleOp MlirModule = Gen->getModule();
148 mlir::MLIRContext &MlirCtx = Gen->getMLIRContext();
149
150 if (!FEOptions.ClangIRDisablePasses) {
151 std::string LibOptOptions = FEOptions.ClangIRLibOptOptions;
152
153 // Setup and run CIR pipeline.
154 const bool EnableLibOpt =
155 FEOptions.ClangIRLibOptEnabled && (CGO.OptimizationLevel > 0);
157 MlirModule, MlirCtx, C, !FEOptions.ClangIRDisableCIRVerifier,
158 FEOptions.ClangIREnableIdiomRecognizer, CGO.OptimizationLevel > 0,
159 EnableLibOpt, LibOptOptions, FEOptions.ClangIRCallConvLowering)
160 .failed()) {
161 // Pass-side errors already routed through ClangIRDiagnosticHandler.
162 // Skip the generic catch-all if a specific diagnostic was emitted.
163 if (!CI.getDiagnostics().hasErrorOccurred())
164 CI.getDiagnostics().Report(diag::err_cir_to_cir_transform_failed);
165 return;
166 }
167 }
168
169 switch (Action) {
171 if (OutputStream && MlirModule) {
172 mlir::OpPrintingFlags Flags;
173 Flags.enableDebugInfo(/*enable=*/true, /*prettyForm=*/false);
174 MlirModule->print(*OutputStream, Flags);
175 }
176 break;
181 StringRef saveTempsPrefix = CGO.SaveTempsFilePrefix;
182 std::string cirSaveTempsOutFile, mlirSaveTempsOutFile;
183 if (!saveTempsPrefix.empty()) {
184 SmallString<128> stem(saveTempsPrefix);
185 llvm::sys::path::replace_extension(stem, "cir");
186 cirSaveTempsOutFile = std::string(stem);
187 llvm::sys::path::replace_extension(stem, "mlir");
188 mlirSaveTempsOutFile = std::string(stem);
189 }
190
191 if (!cirSaveTempsOutFile.empty()) {
192 std::error_code ec;
193 llvm::raw_fd_ostream out(cirSaveTempsOutFile, ec);
194 if (!ec)
195 MlirModule->print(out);
196 }
197
198 std::unique_ptr<llvm::Module> LLVMModule = lowerFromCIRToLLVMIR(
199 MlirModule, LLVMCtx, C.getLangOpts().OpenMP, mlirSaveTempsOutFile,
200 &CI.getVirtualFileSystem());
201
202 if (linkInModules(*LLVMModule))
203 return;
204
207 CI, CI.getCodeGenOpts(), C.getTargetInfo().getDataLayoutString(),
208 LLVMModule.get(), BEAction, FS, std::move(OutputStream));
209 break;
210 }
211 }
212 }
213
214 // TODO: share with BackendConsumer::LinkInModules once OG's CurLinkModule
215 // diagnostic-handler indirection is abstracted behind a callback for CIR.
216 bool linkInModules(llvm::Module &M) {
217 for (auto &LM : LinkModules) {
218 assert(LM.Module && "LinkModule does not actually have a module");
219
220 if (LM.PropagateAttrs)
221 for (llvm::Function &F : *LM.Module) {
222 if (F.isIntrinsic())
223 continue;
225 F, CGO, CI.getLangOpts(), CI.getTargetOpts(), LM.Internalize);
226 }
227
228 bool Err;
229 if (LM.Internalize) {
230 Err = llvm::Linker::linkModules(
231 M, std::move(LM.Module), LM.LinkFlags,
232 [](llvm::Module &M, const llvm::StringSet<> &GVS) {
233 llvm::internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) {
234 return !GV.hasName() || (GVS.count(GV.getName()) == 0);
235 });
236 });
237 } else {
238 Err = llvm::Linker::linkModules(M, std::move(LM.Module), LM.LinkFlags);
239 }
240
241 if (Err)
242 return true;
243 }
244
245 LinkModules.clear();
246 return false;
247 }
248
251 Context->getSourceManager(),
252 "CIR generation of declaration");
253 Gen->HandleTagDeclDefinition(D);
254 }
255
256 void HandleTagDeclRequiredDefinition(const TagDecl *D) override {
257 Gen->HandleTagDeclRequiredDefinition(D);
258 }
259
261 Gen->CompleteTentativeDefinition(D);
262 }
263
264 void HandleVTable(CXXRecordDecl *RD) override { Gen->HandleVTable(RD); }
265};
266} // namespace cir
267
268void CIRGenConsumer::anchor() {}
269
270CIRGenAction::CIRGenAction(OutputType Act, mlir::MLIRContext *MLIRCtx)
271 : MLIRCtx(MLIRCtx ? MLIRCtx : new mlir::MLIRContext),
272 Ctx(std::make_unique<llvm::LLVMContext>()), Action(Act) {}
273
274CIRGenAction::~CIRGenAction() { MLIRMod.release(); }
275
277 if (clang::loadLinkModules(CI, *Ctx, LinkModules))
278 return false;
280}
281
282static std::unique_ptr<raw_pwrite_stream>
283getOutputStream(CompilerInstance &CI, StringRef InFile,
285 switch (Action) {
287 return CI.createDefaultOutputFile(false, InFile, "s");
289 return CI.createDefaultOutputFile(false, InFile, "cir");
291 return CI.createDefaultOutputFile(false, InFile, "ll");
293 return CI.createDefaultOutputFile(true, InFile, "bc");
295 return CI.createDefaultOutputFile(true, InFile, "o");
296 }
297 llvm_unreachable("Invalid CIRGenAction::OutputType");
298}
299
300std::unique_ptr<ASTConsumer>
302 std::unique_ptr<llvm::raw_pwrite_stream> Out = CI.takeOutputStream();
303
304 if (!Out)
305 Out = getOutputStream(CI, InFile, Action);
306
307 auto Result = std::make_unique<cir::CIRGenConsumer>(
308 Action, CI, CI.getCodeGenOpts(), std::move(Out), *Ctx, LinkModules);
309
310 return Result;
311}
312
313void EmitAssemblyAction::anchor() {}
314EmitAssemblyAction::EmitAssemblyAction(mlir::MLIRContext *MLIRCtx)
315 : CIRGenAction(OutputType::EmitAssembly, MLIRCtx) {}
316
317void EmitCIRAction::anchor() {}
318EmitCIRAction::EmitCIRAction(mlir::MLIRContext *MLIRCtx)
319 : CIRGenAction(OutputType::EmitCIR, MLIRCtx) {}
320
321void EmitLLVMAction::anchor() {}
322EmitLLVMAction::EmitLLVMAction(mlir::MLIRContext *MLIRCtx)
323 : CIRGenAction(OutputType::EmitLLVM, MLIRCtx) {}
324
325void EmitBCAction::anchor() {}
326EmitBCAction::EmitBCAction(mlir::MLIRContext *MLIRCtx)
327 : CIRGenAction(OutputType::EmitBC, MLIRCtx) {}
328
329void EmitObjAction::anchor() {}
330EmitObjAction::EmitObjAction(mlir::MLIRContext *MLIRCtx)
331 : CIRGenAction(OutputType::EmitObj, MLIRCtx) {}
Defines the clang::ASTContext interface.
static std::unique_ptr< raw_pwrite_stream > getOutputStream(CompilerInstance &CI, StringRef InFile, CIRGenAction::OutputType Action)
CIRGenAction(OutputType Action, mlir::MLIRContext *MLIRCtx=nullptr)
OutputType Action
bool BeginSourceFileAction(clang::CompilerInstance &CI) override
Callback at the start of processing a single input.
~CIRGenAction() override
std::unique_ptr< clang::ASTConsumer > CreateASTConsumer(clang::CompilerInstance &CI, llvm::StringRef InFile) override
void Initialize(ASTContext &Ctx) override
Initialize - This is called to initialize the consumer, providing the ASTContext.
bool HandleTopLevelDecl(DeclGroupRef D) override
HandleTopLevelDecl - Handle the specified top-level declaration.
void HandleTranslationUnit(ASTContext &C) override
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
bool linkInModules(llvm::Module &M)
void HandleInlineFunctionDefinition(FunctionDecl *D) override
This callback is invoked each time an inline (method or friend) function definition in a class is com...
void CompleteTentativeDefinition(VarDecl *D) override
CompleteTentativeDefinition - Callback invoked at the end of a translation unit to notify the consume...
void HandleTagDeclRequiredDefinition(const TagDecl *D) override
This callback is invoked the first time each TagDecl is required to be complete.
CIRGenConsumer(CIRGenAction::OutputType Action, CompilerInstance &CI, CodeGenOptions &CGO, std::unique_ptr< raw_pwrite_stream > OS, llvm::LLVMContext &LLVMCtx, SmallVectorImpl<::clang::LinkModule > &LinkModules)
void HandleVTable(CXXRecordDecl *RD) override
Callback involved at the end of a translation unit to notify the consumer that a vtable for the given...
void HandleCXXStaticMemberVarInstantiation(clang::VarDecl *VD) override
HandleCXXStaticMemberVarInstantiation - Tell the consumer that this.
void HandleOpenACCRoutineReference(const FunctionDecl *FD, const OpenACCRoutineDecl *RD) override
Callback to handle the end-of-translation unit attachment of OpenACC routine declaration information.
void HandleTagDeclDefinition(TagDecl *D) override
HandleTagDeclDefinition - This callback is invoked each time a TagDecl (e.g.
EmitAssemblyAction(mlir::MLIRContext *MLIRCtx=nullptr)
EmitBCAction(mlir::MLIRContext *MLIRCtx=nullptr)
EmitCIRAction(mlir::MLIRContext *MLIRCtx=nullptr)
EmitLLVMAction(mlir::MLIRContext *MLIRCtx=nullptr)
EmitObjAction(mlir::MLIRContext *MLIRCtx=nullptr)
ASTConsumer - This is an abstract interface that should be implemented by clients that read ASTs.
Definition ASTConsumer.h:35
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
CodeGenOptions - Track various options which control how the code is optimized and passed to the back...
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
std::unique_ptr< raw_pwrite_stream > createDefaultOutputFile(bool Binary=true, StringRef BaseInput="", StringRef Extension="", bool RemoveFileOnSignal=true, bool CreateMissingDirectories=false, bool ForceUseTemporary=false, bool SetOnlyIfDifferent=false)
Create the default output file (from the invocation's options) and add it to the list of tracked outp...
std::unique_ptr< llvm::raw_pwrite_stream > takeOutputStream()
CodeGenOptions & getCodeGenOpts()
virtual bool BeginSourceFileAction(CompilerInstance &CI)
Callback at the start of processing a single input.
FrontendOptions - Options for controlling the behavior of the frontend.
Represents a function declaration or definition.
Definition Decl.h:2058
PrettyStackTraceDecl - If a crash occurs, indicate that it happened when doing something to a specifi...
Definition DeclBase.h:1317
Encodes a location in the source.
Represents the declaration of a struct/union/class/enum.
Definition Decl.h:3851
Represents a variable declaration or definition.
Definition Decl.h:932
std::unique_ptr< llvm::Module > lowerDirectlyFromCIRToLLVMIR(mlir::ModuleOp mlirModule, llvm::LLVMContext &llvmCtx, bool enableOpenMP, llvm::StringRef mlirSaveTempsOutFile={}, llvm::vfs::FileSystem *fs=nullptr)
static BackendAction getBackendActionFromOutputType(CIRGenAction::OutputType Action)
mlir::LogicalResult runCIRToCIRPasses(mlir::ModuleOp theModule, mlir::MLIRContext &mlirCtx, clang::ASTContext &astCtx, bool enableVerifier, bool enableIdiomRecognizer, bool enableCIRSimplify, bool enableLibOpt, llvm::StringRef libOptOptions, bool enableCallConvLowering)
Definition CIRPasses.cpp:77
static std::unique_ptr< llvm::Module > lowerFromCIRToLLVMIR(mlir::ModuleOp MLIRModule, llvm::LLVMContext &LLVMCtx, bool EnableOpenMP, llvm::StringRef mlirSaveTempsOutFile={}, llvm::vfs::FileSystem *fs=nullptr)
void mergeDefaultFunctionDefinitionAttributes(llvm::Function &F, const CodeGenOptions &CodeGenOpts, const LangOptions &LangOpts, const TargetOptions &TargetOpts, bool WillInternalize)
Adds attributes to F according to our CodeGenOpts and LangOpts, as though we had emitted it ourselves...
Definition CGCall.cpp:2484
Top level wrappers for InstallAPI frontend operations.
void emitBackendOutput(CompilerInstance &CI, CodeGenOptions &CGOpts, StringRef TDesc, llvm::Module *M, BackendAction Action, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, std::unique_ptr< raw_pwrite_stream > OS, BackendConsumer *BC=nullptr)
BackendAction
Definition BackendUtil.h:33
@ Backend_EmitAssembly
Emit native assembly files.
Definition BackendUtil.h:34
@ Backend_EmitLL
Emit human-readable LLVM assembly.
Definition BackendUtil.h:36
@ Backend_EmitBC
Emit LLVM bitcode files.
Definition BackendUtil.h:35
@ Backend_EmitObj
Emit native object files.
Definition BackendUtil.h:39
bool loadLinkModules(CompilerInstance &CI, llvm::LLVMContext &Ctx, llvm::SmallVectorImpl< LinkModule > &LinkModules)
Load every bitcode file listed in CodeGenOpts.LinkBitcodeFiles into LinkModules.
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30