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 | |
20 | using namespace cir; |
21 | using namespace clang; |
22 | |
23 | namespace cir { |
24 | |
25 | static BackendAction |
26 | getBackendActionFromOutputType(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 | |
46 | static std::unique_ptr<llvm::Module> |
47 | lowerFromCIRToLLVMIR(mlir::ModuleOp MLIRModule, llvm::LLVMContext &LLVMCtx) { |
48 | return direct::lowerDirectlyFromCIRToLLVMIR(mlirModule: MLIRModule, llvmCtx&: LLVMCtx); |
49 | } |
50 | |
51 | class 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 | |
67 | public: |
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 | |
156 | void CIRGenConsumer::anchor() {} |
157 | |
158 | CIRGenAction::CIRGenAction(OutputType Act, mlir::MLIRContext *MLIRCtx) |
159 | : MLIRCtx(MLIRCtx ? MLIRCtx : new mlir::MLIRContext), Action(Act) {} |
160 | |
161 | CIRGenAction::~CIRGenAction() { MLIRMod.release(); } |
162 | |
163 | static std::unique_ptr<raw_pwrite_stream> |
164 | getOutputStream(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 | |
181 | std::unique_ptr<ASTConsumer> |
182 | CIRGenAction::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 | |
194 | void EmitAssemblyAction::anchor() {} |
195 | EmitAssemblyAction::EmitAssemblyAction(mlir::MLIRContext *MLIRCtx) |
196 | : CIRGenAction(OutputType::EmitAssembly, MLIRCtx) {} |
197 | |
198 | void EmitCIRAction::anchor() {} |
199 | EmitCIRAction::EmitCIRAction(mlir::MLIRContext *MLIRCtx) |
200 | : CIRGenAction(OutputType::EmitCIR, MLIRCtx) {} |
201 | |
202 | void EmitLLVMAction::anchor() {} |
203 | EmitLLVMAction::EmitLLVMAction(mlir::MLIRContext *MLIRCtx) |
204 | : CIRGenAction(OutputType::EmitLLVM, MLIRCtx) {} |
205 | |
206 | void EmitBCAction::anchor() {} |
207 | EmitBCAction::EmitBCAction(mlir::MLIRContext *MLIRCtx) |
208 | : CIRGenAction(OutputType::EmitBC, MLIRCtx) {} |
209 | |
210 | void EmitObjAction::anchor() {} |
211 | EmitObjAction::EmitObjAction(mlir::MLIRContext *MLIRCtx) |
212 | : CIRGenAction(OutputType::EmitObj, MLIRCtx) {} |
213 | |