-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[CIR] Add framework for CIR to LLVM IR lowering #124650
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| //====- LowerToLLVM.h- Lowering from CIR to LLVM --------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file declares an interface for converting CIR modules to LLVM IR. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| #ifndef CLANG_CIR_LOWERTOLLVM_H | ||
| #define CLANG_CIR_LOWERTOLLVM_H | ||
|
|
||
| #include "mlir/Pass/Pass.h" | ||
|
|
||
| #include <memory> | ||
|
|
||
| namespace llvm { | ||
| class LLVMContext; | ||
| class Module; | ||
| } // namespace llvm | ||
|
|
||
| namespace mlir { | ||
| class ModuleOp; | ||
| } // namespace mlir | ||
|
|
||
| namespace cir { | ||
|
|
||
| namespace direct { | ||
| std::unique_ptr<llvm::Module> lowerDirectlyFromCIRToLLVMIR( | ||
| mlir::ModuleOp M, llvm::LLVMContext &Ctx); | ||
| } // namespace direct | ||
| } // namespace cir | ||
|
|
||
| #endif // CLANG_CIR_LOWERTOLLVM_H | ||
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,8 +8,10 @@ | |
|
|
||
| #include "clang/CIR/FrontendAction/CIRGenAction.h" | ||
| #include "clang/CIR/CIRGenerator.h" | ||
| #include "clang/CIR/LowerToLLVM.h" | ||
| #include "clang/CodeGen/BackendUtil.h" | ||
| #include "clang/Frontend/CompilerInstance.h" | ||
|
|
||
| #include "llvm/IR/Module.h" | ||
| #include "mlir/IR/MLIRContext.h" | ||
| #include "mlir/IR/OwningOpRef.h" | ||
|
|
||
|
|
@@ -18,12 +20,30 @@ using namespace clang; | |
|
|
||
| namespace cir { | ||
|
|
||
| static BackendAction | ||
| getBackendActionFromOutputType(CIRGenAction::OutputType Action) { | ||
| switch (Action) { | ||
| case CIRGenAction::OutputType::EmitLLVM: | ||
| return BackendAction::Backend_EmitLL; | ||
| default: | ||
| llvm_unreachable("Unsupported action"); | ||
|
||
| } | ||
| } | ||
|
|
||
| static std::unique_ptr<llvm::Module> lowerFromCIRToLLVMIR( | ||
| const clang::FrontendOptions &FEOpts, mlir::ModuleOp MLIRModule, | ||
| std::unique_ptr<mlir::MLIRContext> MLIRCtx, 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}; | ||
|
|
@@ -32,17 +52,12 @@ class CIRGenConsumer : public clang::ASTConsumer { | |
|
|
||
| public: | ||
| CIRGenConsumer(CIRGenAction::OutputType Action, | ||
| DiagnosticsEngine &DiagnosticsEngine, | ||
| IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, | ||
| const HeaderSearchOptions &HeaderSearchOptions, | ||
| const CodeGenOptions &CodeGenOptions, | ||
| const TargetOptions &TargetOptions, | ||
| const LangOptions &LangOptions, | ||
| const FrontendOptions &FEOptions, | ||
| CompilerInstance &CI, | ||
|
||
| std::unique_ptr<raw_pwrite_stream> OS) | ||
| : Action(Action), OutputStream(std::move(OS)), FS(VFS), | ||
| Gen(std::make_unique<CIRGenerator>(DiagnosticsEngine, std::move(VFS), | ||
| CodeGenOptions)) {} | ||
| : Action(Action), CI(CI), OutputStream(std::move(OS)), | ||
| FS(&CI.getVirtualFileSystem()), | ||
| Gen(std::make_unique<CIRGenerator>(CI.getDiagnostics(), std::move(FS), | ||
| CI.getCodeGenOpts())) {} | ||
|
|
||
| void Initialize(ASTContext &Ctx) override { | ||
| assert(!Context && "initialized multiple times"); | ||
|
|
@@ -58,6 +73,7 @@ class CIRGenConsumer : public clang::ASTConsumer { | |
| void HandleTranslationUnit(ASTContext &C) override { | ||
| Gen->HandleTranslationUnit(C); | ||
| mlir::ModuleOp MlirModule = Gen->getModule(); | ||
| auto MLIRCtx = Gen->takeContext(); | ||
| switch (Action) { | ||
| case CIRGenAction::OutputType::EmitCIR: | ||
| if (OutputStream && MlirModule) { | ||
|
|
@@ -66,6 +82,18 @@ class CIRGenConsumer : public clang::ASTConsumer { | |
| MlirModule->print(*OutputStream, Flags); | ||
| } | ||
| break; | ||
| case CIRGenAction::OutputType::EmitLLVM: { | ||
| llvm::LLVMContext LLVMCtx; | ||
| auto LLVMModule = lowerFromCIRToLLVMIR(CI.getFrontendOpts(), MlirModule, | ||
|
||
| std::move(MLIRCtx), LLVMCtx); | ||
|
|
||
| BackendAction BEAction = getBackendActionFromOutputType(Action); | ||
| emitBackendOutput(CI, CI.getCodeGenOpts(), | ||
| C.getTargetInfo().getDataLayoutString(), | ||
| LLVMModule.get(), BEAction, FS, | ||
| std::move(OutputStream)); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| }; | ||
|
|
@@ -84,6 +112,8 @@ getOutputStream(CompilerInstance &CI, StringRef InFile, | |
| switch (Action) { | ||
| case CIRGenAction::OutputType::EmitCIR: | ||
| return CI.createDefaultOutputFile(false, InFile, "cir"); | ||
| case CIRGenAction::OutputType::EmitLLVM: | ||
| return CI.createDefaultOutputFile(false, InFile, "ll"); | ||
| } | ||
| llvm_unreachable("Invalid CIRGenAction::OutputType"); | ||
| } | ||
|
|
@@ -96,13 +126,15 @@ CIRGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { | |
| Out = getOutputStream(CI, InFile, Action); | ||
|
|
||
| auto Result = std::make_unique<cir::CIRGenConsumer>( | ||
| Action, CI.getDiagnostics(), &CI.getVirtualFileSystem(), | ||
| CI.getHeaderSearchOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(), | ||
| CI.getLangOpts(), CI.getFrontendOpts(), std::move(Out)); | ||
| Action, CI, std::move(Out)); | ||
|
|
||
| return Result; | ||
| } | ||
|
|
||
| void EmitCIRAction::anchor() {} | ||
| EmitCIRAction::EmitCIRAction(mlir::MLIRContext *MLIRCtx) | ||
| : CIRGenAction(OutputType::EmitCIR, MLIRCtx) {} | ||
|
|
||
| void EmitLLVMAction::anchor() {} | ||
| EmitLLVMAction::EmitLLVMAction(mlir::MLIRContext *MLIRCtx) | ||
| : CIRGenAction(OutputType::EmitLLVM, MLIRCtx) {} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| add_subdirectory(DirectToLLVM) | ||
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| set(LLVM_LINK_COMPONENTS | ||
| Core | ||
| Support | ||
| ) | ||
|
|
||
| add_clang_library(clangCIRLoweringDirectToLLVM | ||
| LowerToLLVM.cpp | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| //====- LowerToLLVM.cpp - Lowering from CIR to LLVMIR ---------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file implements lowering of CIR operations to LLVMIR. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "clang/CIR/LowerToLLVM.h" | ||
|
|
||
| #include "mlir/IR/BuiltinOps.h" | ||
| #include "mlir/Pass/Pass.h" | ||
| #include "mlir/Pass/PassManager.h" | ||
| #include "llvm/IR/Module.h" | ||
| #include "llvm/Support/TimeProfiler.h" | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this from include what you use? (Code might be fine, I'm just surprised at how much is required to be included given the implementation.)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry. I was using more of these an an earlier version in my sandbox, and I didn't clean up the includes after I stripped down the patch. |
||
|
|
||
| using namespace cir; | ||
| using namespace llvm; | ||
|
|
||
| namespace cir { | ||
| namespace direct { | ||
|
|
||
| std::unique_ptr<llvm::Module> | ||
| lowerDirectlyFromCIRToLLVMIR(mlir::ModuleOp theModule, LLVMContext &llvmCtx) { | ||
| llvm::TimeTraceScope scope("lower from CIR to LLVM directly"); | ||
|
|
||
| auto ModuleName = theModule.getName(); | ||
|
||
| auto llvmModule = std::make_unique<llvm::Module>(ModuleName ? *ModuleName : "CIRToLLVMModule", llvmCtx); | ||
|
|
||
| if (!llvmModule) | ||
| report_fatal_error("Lowering from LLVMIR dialect to llvm IR failed!"); | ||
|
|
||
| return llvmModule; | ||
| } | ||
| } // namespace direct | ||
| } // namespace cir | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| // Smoke test for ClangIR-to-LLVM IR code generation | ||
| // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s | ||
|
|
||
| // TODO: Add checks when proper lowering is implemented. | ||
| // For now, we're just creating an empty module. | ||
| // CHECK: ModuleID | ||
|
|
||
| void foo() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is somewhat frightning TBH. It potentially leaves the generator in an invalid state. Is there a reason whoever takes this couldn't just keep a reference to this (for vice versa?).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure why it was implemented this way, but I agree with you. In the incubator implementation, the class we're taking it from uses it in the Initialize() function and then never again, but in the Initialize() function it passes this as a raw pointer to one of its contained objects, which keeps it throughout its lifetime. So, we need to keep it around for the lifetime of the generator one way or another. I don't think anything will use it after the point that we take it here, but I also don't see any harm in making it safer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thinks dates back to early prototypes for CIR and clang-tidy integration, but seems like the final version doesn't need it either, see
clang-tools-extra/clang-tidy/cir/Lifetime.cpp. Should be fine to get rid of it.