223 lines · cpp
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-exception6//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 BackendAction26getBackendActionFromOutputType(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 that32 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 through42 // the assert(false) case above43 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, 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>(CI.getDiagnostics(), std::move(FS),73 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(Ctx);80 }81 82 bool HandleTopLevelDecl(DeclGroupRef D) override {83 Gen->HandleTopLevelDecl(D);84 return true;85 }86 87 void HandleCXXStaticMemberVarInstantiation(clang::VarDecl *VD) override {88 Gen->HandleCXXStaticMemberVarInstantiation(VD);89 }90 91 void HandleInlineFunctionDefinition(FunctionDecl *D) override {92 Gen->HandleInlineFunctionDefinition(D);93 }94 95 void HandleTranslationUnit(ASTContext &C) override {96 Gen->HandleTranslationUnit(C);97 98 if (!FEOptions.ClangIRDisableCIRVerifier) {99 if (!Gen->verifyModule()) {100 CI.getDiagnostics().Report(101 diag::err_cir_verification_failed_pre_passes);102 llvm::report_fatal_error(103 "CIR codegen: module verification error before running CIR passes");104 return;105 }106 }107 108 mlir::ModuleOp MlirModule = Gen->getModule();109 mlir::MLIRContext &MlirCtx = Gen->getMLIRContext();110 111 if (!FEOptions.ClangIRDisablePasses) {112 // Setup and run CIR pipeline.113 if (runCIRToCIRPasses(MlirModule, MlirCtx, C,114 !FEOptions.ClangIRDisableCIRVerifier,115 CGO.OptimizationLevel > 0)116 .failed()) {117 CI.getDiagnostics().Report(diag::err_cir_to_cir_transform_failed);118 return;119 }120 }121 122 switch (Action) {123 case CIRGenAction::OutputType::EmitCIR:124 if (OutputStream && MlirModule) {125 mlir::OpPrintingFlags Flags;126 Flags.enableDebugInfo(/*enable=*/true, /*prettyForm=*/false);127 MlirModule->print(*OutputStream, Flags);128 }129 break;130 case CIRGenAction::OutputType::EmitLLVM:131 case CIRGenAction::OutputType::EmitBC:132 case CIRGenAction::OutputType::EmitObj:133 case CIRGenAction::OutputType::EmitAssembly: {134 llvm::LLVMContext LLVMCtx;135 std::unique_ptr<llvm::Module> LLVMModule =136 lowerFromCIRToLLVMIR(MlirModule, LLVMCtx);137 138 BackendAction BEAction = getBackendActionFromOutputType(Action);139 emitBackendOutput(140 CI, CI.getCodeGenOpts(), C.getTargetInfo().getDataLayoutString(),141 LLVMModule.get(), BEAction, FS, std::move(OutputStream));142 break;143 }144 }145 }146 147 void HandleTagDeclDefinition(TagDecl *D) override {148 PrettyStackTraceDecl CrashInfo(D, SourceLocation(),149 Context->getSourceManager(),150 "CIR generation of declaration");151 Gen->HandleTagDeclDefinition(D);152 }153 154 void HandleTagDeclRequiredDefinition(const TagDecl *D) override {155 Gen->HandleTagDeclRequiredDefinition(D);156 }157 158 void CompleteTentativeDefinition(VarDecl *D) override {159 Gen->CompleteTentativeDefinition(D);160 }161 162 void HandleVTable(CXXRecordDecl *RD) override { Gen->HandleVTable(RD); }163};164} // namespace cir165 166void CIRGenConsumer::anchor() {}167 168CIRGenAction::CIRGenAction(OutputType Act, mlir::MLIRContext *MLIRCtx)169 : MLIRCtx(MLIRCtx ? MLIRCtx : new mlir::MLIRContext), Action(Act) {}170 171CIRGenAction::~CIRGenAction() { MLIRMod.release(); }172 173static std::unique_ptr<raw_pwrite_stream>174getOutputStream(CompilerInstance &CI, StringRef InFile,175 CIRGenAction::OutputType Action) {176 switch (Action) {177 case CIRGenAction::OutputType::EmitAssembly:178 return CI.createDefaultOutputFile(false, InFile, "s");179 case CIRGenAction::OutputType::EmitCIR:180 return CI.createDefaultOutputFile(false, InFile, "cir");181 case CIRGenAction::OutputType::EmitLLVM:182 return CI.createDefaultOutputFile(false, InFile, "ll");183 case CIRGenAction::OutputType::EmitBC:184 return CI.createDefaultOutputFile(true, InFile, "bc");185 case CIRGenAction::OutputType::EmitObj:186 return CI.createDefaultOutputFile(true, InFile, "o");187 }188 llvm_unreachable("Invalid CIRGenAction::OutputType");189}190 191std::unique_ptr<ASTConsumer>192CIRGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {193 std::unique_ptr<llvm::raw_pwrite_stream> Out = CI.takeOutputStream();194 195 if (!Out)196 Out = getOutputStream(CI, InFile, Action);197 198 auto Result = std::make_unique<cir::CIRGenConsumer>(199 Action, CI, CI.getCodeGenOpts(), std::move(Out));200 201 return Result;202}203 204void EmitAssemblyAction::anchor() {}205EmitAssemblyAction::EmitAssemblyAction(mlir::MLIRContext *MLIRCtx)206 : CIRGenAction(OutputType::EmitAssembly, MLIRCtx) {}207 208void EmitCIRAction::anchor() {}209EmitCIRAction::EmitCIRAction(mlir::MLIRContext *MLIRCtx)210 : CIRGenAction(OutputType::EmitCIR, MLIRCtx) {}211 212void EmitLLVMAction::anchor() {}213EmitLLVMAction::EmitLLVMAction(mlir::MLIRContext *MLIRCtx)214 : CIRGenAction(OutputType::EmitLLVM, MLIRCtx) {}215 216void EmitBCAction::anchor() {}217EmitBCAction::EmitBCAction(mlir::MLIRContext *MLIRCtx)218 : CIRGenAction(OutputType::EmitBC, MLIRCtx) {}219 220void EmitObjAction::anchor() {}221EmitObjAction::EmitObjAction(mlir::MLIRContext *MLIRCtx)222 : CIRGenAction(OutputType::EmitObj, MLIRCtx) {}223