mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 06:36:05 +00:00

This change introduces the cir-canonicalize pass. This is a simple cir-to-cir transformation that eliminates empty scopes and redundant branches. It will be expanded in future changes to simplify other redundant instruction sequences. MLIR verification and mlir-specific command-line option handling is also introduced here.
196 lines
6.5 KiB
C++
196 lines
6.5 KiB
C++
//===--- CIRGenAction.cpp - LLVM Code generation Frontend Action ---------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/CIR/FrontendAction/CIRGenAction.h"
|
|
#include "mlir/IR/MLIRContext.h"
|
|
#include "mlir/IR/OwningOpRef.h"
|
|
#include "clang/Basic/DiagnosticFrontend.h"
|
|
#include "clang/CIR/CIRGenerator.h"
|
|
#include "clang/CIR/CIRToCIRPasses.h"
|
|
#include "clang/CIR/LowerToLLVM.h"
|
|
#include "clang/CodeGen/BackendUtil.h"
|
|
#include "clang/Frontend/CompilerInstance.h"
|
|
#include "llvm/IR/Module.h"
|
|
|
|
using namespace cir;
|
|
using namespace clang;
|
|
|
|
namespace cir {
|
|
|
|
static BackendAction
|
|
getBackendActionFromOutputType(CIRGenAction::OutputType Action) {
|
|
switch (Action) {
|
|
case CIRGenAction::OutputType::EmitCIR:
|
|
assert(false &&
|
|
"Unsupported output type for getBackendActionFromOutputType!");
|
|
break; // Unreachable, but fall through to report that
|
|
case CIRGenAction::OutputType::EmitAssembly:
|
|
return BackendAction::Backend_EmitAssembly;
|
|
case CIRGenAction::OutputType::EmitBC:
|
|
return BackendAction::Backend_EmitBC;
|
|
case CIRGenAction::OutputType::EmitLLVM:
|
|
return BackendAction::Backend_EmitLL;
|
|
case CIRGenAction::OutputType::EmitObj:
|
|
return BackendAction::Backend_EmitObj;
|
|
}
|
|
// We should only get here if a non-enum value is passed in or we went through
|
|
// the assert(false) case above
|
|
llvm_unreachable("Unsupported output type!");
|
|
}
|
|
|
|
static std::unique_ptr<llvm::Module>
|
|
lowerFromCIRToLLVMIR(mlir::ModuleOp MLIRModule, llvm::LLVMContext &LLVMCtx) {
|
|
return direct::lowerDirectlyFromCIRToLLVMIR(MLIRModule, LLVMCtx);
|
|
}
|
|
|
|
class CIRGenConsumer : public clang::ASTConsumer {
|
|
|
|
virtual void anchor();
|
|
|
|
CIRGenAction::OutputType Action;
|
|
|
|
CompilerInstance &CI;
|
|
|
|
std::unique_ptr<raw_pwrite_stream> OutputStream;
|
|
|
|
ASTContext *Context{nullptr};
|
|
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
|
|
std::unique_ptr<CIRGenerator> Gen;
|
|
const FrontendOptions &FEOptions;
|
|
|
|
public:
|
|
CIRGenConsumer(CIRGenAction::OutputType Action, CompilerInstance &CI,
|
|
std::unique_ptr<raw_pwrite_stream> OS)
|
|
: Action(Action), CI(CI), OutputStream(std::move(OS)),
|
|
FS(&CI.getVirtualFileSystem()),
|
|
Gen(std::make_unique<CIRGenerator>(CI.getDiagnostics(), std::move(FS),
|
|
CI.getCodeGenOpts())),
|
|
FEOptions(CI.getFrontendOpts()) {}
|
|
|
|
void Initialize(ASTContext &Ctx) override {
|
|
assert(!Context && "initialized multiple times");
|
|
Context = &Ctx;
|
|
Gen->Initialize(Ctx);
|
|
}
|
|
|
|
bool HandleTopLevelDecl(DeclGroupRef D) override {
|
|
Gen->HandleTopLevelDecl(D);
|
|
return true;
|
|
}
|
|
|
|
void HandleTranslationUnit(ASTContext &C) override {
|
|
Gen->HandleTranslationUnit(C);
|
|
|
|
if (!FEOptions.ClangIRDisableCIRVerifier) {
|
|
if (!Gen->verifyModule()) {
|
|
CI.getDiagnostics().Report(
|
|
diag::err_cir_verification_failed_pre_passes);
|
|
llvm::report_fatal_error(
|
|
"CIR codegen: module verification error before running CIR passes");
|
|
return;
|
|
}
|
|
}
|
|
|
|
mlir::ModuleOp MlirModule = Gen->getModule();
|
|
mlir::MLIRContext &MlirCtx = Gen->getMLIRContext();
|
|
|
|
if (!FEOptions.ClangIRDisablePasses) {
|
|
// Setup and run CIR pipeline.
|
|
if (runCIRToCIRPasses(MlirModule, MlirCtx, C,
|
|
!FEOptions.ClangIRDisableCIRVerifier)
|
|
.failed()) {
|
|
CI.getDiagnostics().Report(diag::err_cir_to_cir_transform_failed);
|
|
return;
|
|
}
|
|
}
|
|
|
|
switch (Action) {
|
|
case CIRGenAction::OutputType::EmitCIR:
|
|
if (OutputStream && MlirModule) {
|
|
mlir::OpPrintingFlags Flags;
|
|
Flags.enableDebugInfo(/*enable=*/true, /*prettyForm=*/false);
|
|
MlirModule->print(*OutputStream, Flags);
|
|
}
|
|
break;
|
|
case CIRGenAction::OutputType::EmitLLVM:
|
|
case CIRGenAction::OutputType::EmitBC:
|
|
case CIRGenAction::OutputType::EmitObj:
|
|
case CIRGenAction::OutputType::EmitAssembly: {
|
|
llvm::LLVMContext LLVMCtx;
|
|
std::unique_ptr<llvm::Module> LLVMModule =
|
|
lowerFromCIRToLLVMIR(MlirModule, LLVMCtx);
|
|
|
|
BackendAction BEAction = getBackendActionFromOutputType(Action);
|
|
emitBackendOutput(
|
|
CI, CI.getCodeGenOpts(), C.getTargetInfo().getDataLayoutString(),
|
|
LLVMModule.get(), BEAction, FS, std::move(OutputStream));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
} // namespace cir
|
|
|
|
void CIRGenConsumer::anchor() {}
|
|
|
|
CIRGenAction::CIRGenAction(OutputType Act, mlir::MLIRContext *MLIRCtx)
|
|
: MLIRCtx(MLIRCtx ? MLIRCtx : new mlir::MLIRContext), Action(Act) {}
|
|
|
|
CIRGenAction::~CIRGenAction() { MLIRMod.release(); }
|
|
|
|
static std::unique_ptr<raw_pwrite_stream>
|
|
getOutputStream(CompilerInstance &CI, StringRef InFile,
|
|
CIRGenAction::OutputType Action) {
|
|
switch (Action) {
|
|
case CIRGenAction::OutputType::EmitAssembly:
|
|
return CI.createDefaultOutputFile(false, InFile, "s");
|
|
case CIRGenAction::OutputType::EmitCIR:
|
|
return CI.createDefaultOutputFile(false, InFile, "cir");
|
|
case CIRGenAction::OutputType::EmitLLVM:
|
|
return CI.createDefaultOutputFile(false, InFile, "ll");
|
|
case CIRGenAction::OutputType::EmitBC:
|
|
return CI.createDefaultOutputFile(true, InFile, "bc");
|
|
case CIRGenAction::OutputType::EmitObj:
|
|
return CI.createDefaultOutputFile(true, InFile, "o");
|
|
}
|
|
llvm_unreachable("Invalid CIRGenAction::OutputType");
|
|
}
|
|
|
|
std::unique_ptr<ASTConsumer>
|
|
CIRGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
|
|
std::unique_ptr<llvm::raw_pwrite_stream> Out = CI.takeOutputStream();
|
|
|
|
if (!Out)
|
|
Out = getOutputStream(CI, InFile, Action);
|
|
|
|
auto Result =
|
|
std::make_unique<cir::CIRGenConsumer>(Action, CI, std::move(Out));
|
|
|
|
return Result;
|
|
}
|
|
|
|
void EmitAssemblyAction::anchor() {}
|
|
EmitAssemblyAction::EmitAssemblyAction(mlir::MLIRContext *MLIRCtx)
|
|
: CIRGenAction(OutputType::EmitAssembly, MLIRCtx) {}
|
|
|
|
void EmitCIRAction::anchor() {}
|
|
EmitCIRAction::EmitCIRAction(mlir::MLIRContext *MLIRCtx)
|
|
: CIRGenAction(OutputType::EmitCIR, MLIRCtx) {}
|
|
|
|
void EmitLLVMAction::anchor() {}
|
|
EmitLLVMAction::EmitLLVMAction(mlir::MLIRContext *MLIRCtx)
|
|
: CIRGenAction(OutputType::EmitLLVM, MLIRCtx) {}
|
|
|
|
void EmitBCAction::anchor() {}
|
|
EmitBCAction::EmitBCAction(mlir::MLIRContext *MLIRCtx)
|
|
: CIRGenAction(OutputType::EmitBC, MLIRCtx) {}
|
|
|
|
void EmitObjAction::anchor() {}
|
|
EmitObjAction::EmitObjAction(mlir::MLIRContext *MLIRCtx)
|
|
: CIRGenAction(OutputType::EmitObj, MLIRCtx) {}
|