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
9#include "clang/CIR/FrontendAction/CIRGenAction.h"
10#include "mlir/IR/MLIRContext.h"
11#include "mlir/IR/OwningOpRef.h"
12#include "clang/Basic/DiagnosticFrontend.h"
13#include "clang/CIR/CIRGenerator.h"
14#include "clang/CIR/CIRToCIRPasses.h"
15#include "clang/CIR/LowerToLLVM.h"
16#include "clang/CodeGen/BackendUtil.h"
17#include "clang/Frontend/CompilerInstance.h"
18#include "llvm/IR/Module.h"
19
20using namespace cir;
21using namespace clang;
22
23namespace cir {
24
25static BackendAction
26getBackendActionFromOutputType(CIRGenAction::OutputType Action) {
27 switch (Action) {
28 case CIRGenAction::OutputType::EmitCIR:
29 assert(false &&
30 "Unsupported output type for getBackendActionFromOutputType!");
31 break; // Unreachable, but fall through to report that
32 case CIRGenAction::OutputType::EmitAssembly:
33 return BackendAction::Backend_EmitAssembly;
34 case CIRGenAction::OutputType::EmitBC:
35 return BackendAction::Backend_EmitBC;
36 case CIRGenAction::OutputType::EmitLLVM:
37 return BackendAction::Backend_EmitLL;
38 case CIRGenAction::OutputType::EmitObj:
39 return BackendAction::Backend_EmitObj;
40 }
41 // We should only get here if a non-enum value is passed in or we went through
42 // the assert(false) case above
43 llvm_unreachable("Unsupported output type!");
44}
45
46static std::unique_ptr<llvm::Module>
47lowerFromCIRToLLVMIR(mlir::ModuleOp MLIRModule, llvm::LLVMContext &LLVMCtx) {
48 return direct::lowerDirectlyFromCIRToLLVMIR(mlirModule: MLIRModule, llvmCtx&: LLVMCtx);
49}
50
51class CIRGenConsumer : public clang::ASTConsumer {
52
53 virtual void anchor();
54
55 CIRGenAction::OutputType Action;
56
57 CompilerInstance &CI;
58
59 std::unique_ptr<raw_pwrite_stream> OutputStream;
60
61 ASTContext *Context{nullptr};
62 IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
63 std::unique_ptr<CIRGenerator> Gen;
64 const FrontendOptions &FEOptions;
65 CodeGenOptions &CGO;
66
67public:
68 CIRGenConsumer(CIRGenAction::OutputType Action, CompilerInstance &CI,
69 CodeGenOptions &CGO, std::unique_ptr<raw_pwrite_stream> OS)
70 : Action(Action), CI(CI), OutputStream(std::move(OS)),
71 FS(&CI.getVirtualFileSystem()),
72 Gen(std::make_unique<CIRGenerator>(args&: CI.getDiagnostics(), args: std::move(FS),
73 args&: CI.getCodeGenOpts())),
74 FEOptions(CI.getFrontendOpts()), CGO(CGO) {}
75
76 void Initialize(ASTContext &Ctx) override {
77 assert(!Context && "initialized multiple times");
78 Context = &Ctx;
79 Gen->Initialize(astContext&: Ctx);
80 }
81
82 bool HandleTopLevelDecl(DeclGroupRef D) override {
83 Gen->HandleTopLevelDecl(group: D);
84 return true;
85 }
86
87 void HandleInlineFunctionDefinition(FunctionDecl *D) override {
88 Gen->HandleInlineFunctionDefinition(d: D);
89 }
90
91 void HandleTranslationUnit(ASTContext &C) override {
92 Gen->HandleTranslationUnit(astContext&: C);
93
94 if (!FEOptions.ClangIRDisableCIRVerifier) {
95 if (!Gen->verifyModule()) {
96 CI.getDiagnostics().Report(
97 diag::err_cir_verification_failed_pre_passes);
98 llvm::report_fatal_error(
99 reason: "CIR codegen: module verification error before running CIR passes");
100 return;
101 }
102 }
103
104 mlir::ModuleOp MlirModule = Gen->getModule();
105 mlir::MLIRContext &MlirCtx = Gen->getMLIRContext();
106
107 if (!FEOptions.ClangIRDisablePasses) {
108 // Setup and run CIR pipeline.
109 if (runCIRToCIRPasses(MlirModule, MlirCtx, C,
110 !FEOptions.ClangIRDisableCIRVerifier,
111 CGO.OptimizationLevel > 0)
112 .failed()) {
113 CI.getDiagnostics().Report(diag::err_cir_to_cir_transform_failed);
114 return;
115 }
116 }
117
118 switch (Action) {
119 case CIRGenAction::OutputType::EmitCIR:
120 if (OutputStream && MlirModule) {
121 mlir::OpPrintingFlags Flags;
122 Flags.enableDebugInfo(/*enable=*/true, /*prettyForm=*/false);
123 MlirModule->print(*OutputStream, Flags);
124 }
125 break;
126 case CIRGenAction::OutputType::EmitLLVM:
127 case CIRGenAction::OutputType::EmitBC:
128 case CIRGenAction::OutputType::EmitObj:
129 case CIRGenAction::OutputType::EmitAssembly: {
130 llvm::LLVMContext LLVMCtx;
131 std::unique_ptr<llvm::Module> LLVMModule =
132 lowerFromCIRToLLVMIR(MlirModule, LLVMCtx);
133
134 BackendAction BEAction = getBackendActionFromOutputType(Action);
135 emitBackendOutput(
136 CI, CGOpts&: CI.getCodeGenOpts(), TDesc: C.getTargetInfo().getDataLayoutString(),
137 M: LLVMModule.get(), Action: BEAction, VFS: FS, OS: std::move(OutputStream));
138 break;
139 }
140 }
141 }
142
143 void HandleTagDeclDefinition(TagDecl *D) override {
144 PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
145 Context->getSourceManager(),
146 "CIR generation of declaration");
147 Gen->HandleTagDeclDefinition(d: D);
148 }
149
150 void CompleteTentativeDefinition(VarDecl *D) override {
151 Gen->CompleteTentativeDefinition(d: D);
152 }
153};
154} // namespace cir
155
156void CIRGenConsumer::anchor() {}
157
158CIRGenAction::CIRGenAction(OutputType Act, mlir::MLIRContext *MLIRCtx)
159 : MLIRCtx(MLIRCtx ? MLIRCtx : new mlir::MLIRContext), Action(Act) {}
160
161CIRGenAction::~CIRGenAction() { MLIRMod.release(); }
162
163static std::unique_ptr<raw_pwrite_stream>
164getOutputStream(CompilerInstance &CI, StringRef InFile,
165 CIRGenAction::OutputType Action) {
166 switch (Action) {
167 case CIRGenAction::OutputType::EmitAssembly:
168 return CI.createDefaultOutputFile(Binary: false, BaseInput: InFile, Extension: "s");
169 case CIRGenAction::OutputType::EmitCIR:
170 return CI.createDefaultOutputFile(Binary: false, BaseInput: InFile, Extension: "cir");
171 case CIRGenAction::OutputType::EmitLLVM:
172 return CI.createDefaultOutputFile(Binary: false, BaseInput: InFile, Extension: "ll");
173 case CIRGenAction::OutputType::EmitBC:
174 return CI.createDefaultOutputFile(Binary: true, BaseInput: InFile, Extension: "bc");
175 case CIRGenAction::OutputType::EmitObj:
176 return CI.createDefaultOutputFile(Binary: true, BaseInput: InFile, Extension: "o");
177 }
178 llvm_unreachable("Invalid CIRGenAction::OutputType");
179}
180
181std::unique_ptr<ASTConsumer>
182CIRGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
183 std::unique_ptr<llvm::raw_pwrite_stream> Out = CI.takeOutputStream();
184
185 if (!Out)
186 Out = getOutputStream(CI, InFile, Action);
187
188 auto Result = std::make_unique<cir::CIRGenConsumer>(
189 args&: Action, args&: CI, args&: CI.getCodeGenOpts(), args: std::move(Out));
190
191 return Result;
192}
193
194void EmitAssemblyAction::anchor() {}
195EmitAssemblyAction::EmitAssemblyAction(mlir::MLIRContext *MLIRCtx)
196 : CIRGenAction(OutputType::EmitAssembly, MLIRCtx) {}
197
198void EmitCIRAction::anchor() {}
199EmitCIRAction::EmitCIRAction(mlir::MLIRContext *MLIRCtx)
200 : CIRGenAction(OutputType::EmitCIR, MLIRCtx) {}
201
202void EmitLLVMAction::anchor() {}
203EmitLLVMAction::EmitLLVMAction(mlir::MLIRContext *MLIRCtx)
204 : CIRGenAction(OutputType::EmitLLVM, MLIRCtx) {}
205
206void EmitBCAction::anchor() {}
207EmitBCAction::EmitBCAction(mlir::MLIRContext *MLIRCtx)
208 : CIRGenAction(OutputType::EmitBC, MLIRCtx) {}
209
210void EmitObjAction::anchor() {}
211EmitObjAction::EmitObjAction(mlir::MLIRContext *MLIRCtx)
212 : CIRGenAction(OutputType::EmitObj, MLIRCtx) {}
213

source code of clang/lib/CIR/FrontendAction/CIRGenAction.cpp