CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
311 lines
11 KiB
C++
311 lines
11 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/CodeGen/ModuleLinker.h"
|
|
#include "clang/Frontend/CompilerInstance.h"
|
|
#include "llvm/ADT/ScopeExit.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/ADT/StringSet.h"
|
|
#include "llvm/IR/DiagnosticHandler.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/GlobalValue.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/Linker/Linker.h"
|
|
#include "llvm/Support/Path.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/Transforms/IPO/Internalize.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,
|
|
llvm::StringRef mlirSaveTempsOutFile = {},
|
|
llvm::vfs::FileSystem *fs = nullptr) {
|
|
return direct::lowerDirectlyFromCIRToLLVMIR(MLIRModule, LLVMCtx,
|
|
mlirSaveTempsOutFile, fs);
|
|
}
|
|
|
|
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;
|
|
CodeGenOptions &CGO;
|
|
|
|
llvm::LLVMContext &LLVMCtx;
|
|
SmallVectorImpl<::clang::LinkModule> &LinkModules;
|
|
|
|
public:
|
|
CIRGenConsumer(CIRGenAction::OutputType Action, CompilerInstance &CI,
|
|
CodeGenOptions &CGO, std::unique_ptr<raw_pwrite_stream> OS,
|
|
llvm::LLVMContext &LLVMCtx,
|
|
SmallVectorImpl<::clang::LinkModule> &LinkModules)
|
|
: 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()), CGO(CGO), LLVMCtx(LLVMCtx),
|
|
LinkModules(LinkModules) {}
|
|
|
|
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 HandleCXXStaticMemberVarInstantiation(clang::VarDecl *VD) override {
|
|
Gen->HandleCXXStaticMemberVarInstantiation(VD);
|
|
}
|
|
|
|
void HandleOpenACCRoutineReference(const FunctionDecl *FD,
|
|
const OpenACCRoutineDecl *RD) override {
|
|
Gen->HandleOpenACCRoutineReference(FD, RD);
|
|
}
|
|
|
|
void HandleInlineFunctionDefinition(FunctionDecl *D) override {
|
|
Gen->HandleInlineFunctionDefinition(D);
|
|
}
|
|
|
|
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,
|
|
FEOptions.ClangIREnableIdiomRecognizer, CGO.OptimizationLevel > 0)
|
|
.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: {
|
|
StringRef saveTempsPrefix = CGO.SaveTempsFilePrefix;
|
|
std::string cirSaveTempsOutFile, mlirSaveTempsOutFile;
|
|
if (!saveTempsPrefix.empty()) {
|
|
SmallString<128> stem(saveTempsPrefix);
|
|
llvm::sys::path::replace_extension(stem, "cir");
|
|
cirSaveTempsOutFile = std::string(stem);
|
|
llvm::sys::path::replace_extension(stem, "mlir");
|
|
mlirSaveTempsOutFile = std::string(stem);
|
|
}
|
|
|
|
if (!cirSaveTempsOutFile.empty()) {
|
|
std::error_code ec;
|
|
llvm::raw_fd_ostream out(cirSaveTempsOutFile, ec);
|
|
if (!ec)
|
|
MlirModule->print(out);
|
|
}
|
|
|
|
std::unique_ptr<llvm::Module> LLVMModule =
|
|
lowerFromCIRToLLVMIR(MlirModule, LLVMCtx, mlirSaveTempsOutFile,
|
|
&CI.getVirtualFileSystem());
|
|
|
|
if (linkInModules(*LLVMModule))
|
|
return;
|
|
|
|
BackendAction BEAction = getBackendActionFromOutputType(Action);
|
|
emitBackendOutput(
|
|
CI, CI.getCodeGenOpts(), C.getTargetInfo().getDataLayoutString(),
|
|
LLVMModule.get(), BEAction, FS, std::move(OutputStream));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: share with BackendConsumer::LinkInModules once OG's CurLinkModule
|
|
// diagnostic-handler indirection is abstracted behind a callback for CIR.
|
|
bool linkInModules(llvm::Module &M) {
|
|
for (auto &LM : LinkModules) {
|
|
assert(LM.Module && "LinkModule does not actually have a module");
|
|
|
|
if (LM.PropagateAttrs)
|
|
for (llvm::Function &F : *LM.Module) {
|
|
if (F.isIntrinsic())
|
|
continue;
|
|
clang::CodeGen::mergeDefaultFunctionDefinitionAttributes(
|
|
F, CGO, CI.getLangOpts(), CI.getTargetOpts(), LM.Internalize);
|
|
}
|
|
|
|
bool Err;
|
|
if (LM.Internalize) {
|
|
Err = llvm::Linker::linkModules(
|
|
M, std::move(LM.Module), LM.LinkFlags,
|
|
[](llvm::Module &M, const llvm::StringSet<> &GVS) {
|
|
llvm::internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) {
|
|
return !GV.hasName() || (GVS.count(GV.getName()) == 0);
|
|
});
|
|
});
|
|
} else {
|
|
Err = llvm::Linker::linkModules(M, std::move(LM.Module), LM.LinkFlags);
|
|
}
|
|
|
|
if (Err)
|
|
return true;
|
|
}
|
|
|
|
LinkModules.clear();
|
|
return false;
|
|
}
|
|
|
|
void HandleTagDeclDefinition(TagDecl *D) override {
|
|
PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
|
|
Context->getSourceManager(),
|
|
"CIR generation of declaration");
|
|
Gen->HandleTagDeclDefinition(D);
|
|
}
|
|
|
|
void HandleTagDeclRequiredDefinition(const TagDecl *D) override {
|
|
Gen->HandleTagDeclRequiredDefinition(D);
|
|
}
|
|
|
|
void CompleteTentativeDefinition(VarDecl *D) override {
|
|
Gen->CompleteTentativeDefinition(D);
|
|
}
|
|
|
|
void HandleVTable(CXXRecordDecl *RD) override { Gen->HandleVTable(RD); }
|
|
};
|
|
} // namespace cir
|
|
|
|
void CIRGenConsumer::anchor() {}
|
|
|
|
CIRGenAction::CIRGenAction(OutputType Act, mlir::MLIRContext *MLIRCtx)
|
|
: MLIRCtx(MLIRCtx ? MLIRCtx : new mlir::MLIRContext),
|
|
Ctx(std::make_unique<llvm::LLVMContext>()), Action(Act) {}
|
|
|
|
CIRGenAction::~CIRGenAction() { MLIRMod.release(); }
|
|
|
|
bool CIRGenAction::BeginSourceFileAction(CompilerInstance &CI) {
|
|
if (clang::loadLinkModules(CI, *Ctx, LinkModules))
|
|
return false;
|
|
return ASTFrontendAction::BeginSourceFileAction(CI);
|
|
}
|
|
|
|
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, CI.getCodeGenOpts(), std::move(Out), *Ctx, LinkModules);
|
|
|
|
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) {}
|