Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions clang/include/clang/CIR/FrontendAction/CIRGenAction.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class CIRGenAction : public clang::ASTFrontendAction {
public:
enum class OutputType {
EmitCIR,
EmitLLVM,
};

private:
Expand Down Expand Up @@ -55,6 +56,13 @@ class EmitCIRAction : public CIRGenAction {
EmitCIRAction(mlir::MLIRContext *MLIRCtx = nullptr);
};

class EmitLLVMAction : public CIRGenAction {
virtual void anchor();

public:
EmitLLVMAction(mlir::MLIRContext *MLIRCtx = nullptr);
};

} // namespace cir

#endif
36 changes: 36 additions & 0 deletions clang/include/clang/CIR/LowerToLLVM.h
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
1 change: 1 addition & 0 deletions clang/lib/CIR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ add_subdirectory(Dialect)
add_subdirectory(CodeGen)
add_subdirectory(FrontendAction)
add_subdirectory(Interfaces)
add_subdirectory(Lowering)
69 changes: 51 additions & 18 deletions clang/lib/CIR/FrontendAction/CIRGenAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,60 @@
//===----------------------------------------------------------------------===//

#include "clang/CIR/FrontendAction/CIRGenAction.h"
#include "clang/CIR/CIRGenerator.h"
#include "clang/Frontend/CompilerInstance.h"

#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/OwningOpRef.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"

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::EmitLLVM:
return BackendAction::Backend_EmitLL;
}
// 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;

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,
CIRGenConsumer(CIRGenAction::OutputType Action, 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");
Expand All @@ -66,6 +84,17 @@ class CIRGenConsumer : public clang::ASTConsumer {
MlirModule->print(*OutputStream, Flags);
}
break;
case CIRGenAction::OutputType::EmitLLVM: {
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;
}
}
}
};
Expand All @@ -84,6 +113,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");
}
Expand All @@ -95,14 +126,16 @@ CIRGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
if (!Out)
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));
auto Result =
std::make_unique<cir::CIRGenConsumer>(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) {}
1 change: 1 addition & 0 deletions clang/lib/CIR/FrontendAction/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ add_clang_library(clangCIRFrontendAction
clangAST
clangFrontend
clangCIR
clangCIRLoweringDirectToLLVM
MLIRCIR
MLIRIR
)
1 change: 1 addition & 0 deletions clang/lib/CIR/Lowering/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_subdirectory(DirectToLLVM)
8 changes: 8 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt
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
)
39 changes: 39 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//====- 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 "llvm/IR/Module.h"
#include "llvm/Support/TimeProfiler.h"

using namespace cir;
using namespace llvm;

namespace cir {
namespace direct {

std::unique_ptr<llvm::Module>
lowerDirectlyFromCIRToLLVMIR(mlir::ModuleOp MOp, LLVMContext &LLVMCtx) {
llvm::TimeTraceScope scope("lower from CIR to LLVM directly");

std::optional<StringRef> ModuleName = MOp.getName();
auto M = std::make_unique<llvm::Module>(
ModuleName ? *ModuleName : "CIRToLLVMModule", LLVMCtx);

if (!M)
report_fatal_error("Lowering from LLVMIR dialect to llvm IR failed!");
Comment on lines +33 to +34
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this mostly for debugging purposes while we get stuff up and running? The concern here is that CIR is a library interface and reporting a fatal error would be frustrating if the consumer of the library has different ideas about how to handle such a failure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The incubator implementation uses report_fatal_error in several situations similar to this. I don't know if it was intended as a temporary measure or not. Is the right way to handle this passing in a reference to a DiagnosticsEngine?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"It depends" (sorry for the total non-answer, lol).

If the reason for the failure is because of user error, then we would want to thread in a DiagnosticsEngine so we can report diagnostics the usual way.

If the reason for the failure is because the CIR developer is holding things wrong, then we probably would want an assertion closer to the actual issue, and then silently return null here.

If the reason for the failure leads to "there's no way to recover from this, everything is in a horrible state", then report_fatal_error is more reasonable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User errors will have been reported before this. I think the expectation is that we shouldn't hit this failure, but while the CIR code is still partially implemented we probably will. For now, this is kind of acting as a backstop against failures. So, returning to your original question, I think, yes, this is "mostly for debugging purposes while we get stuff up and running."

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the things using llvmModule in CIR do probably already emit errors before hitting this. However, there are functions outside CIR that take a llvmModule that we don't control but we use (e.g. prepareLLVMModule), and report_fatal_error is an extra mechanism to make sure compilation chokes if something weird comes out of it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a temporary measure, this is fine to leave in for now. However, I think this should migrate away from report_fatal_error in the future so that consumers of the library have the freedom to handle failures more gracefully (an assert would be reasonable).


return M;
}
} // namespace direct
} // namespace cir
8 changes: 7 additions & 1 deletion clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,13 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
llvm_unreachable("CIR suppport not built into clang");
#endif
case EmitHTML: return std::make_unique<HTMLPrintAction>();
case EmitLLVM: return std::make_unique<EmitLLVMAction>();
case EmitLLVM: {
#if CLANG_ENABLE_CIR
if (UseCIR)
return std::make_unique<cir::EmitLLVMAction>();
#endif
return std::make_unique<EmitLLVMAction>();
}
case EmitLLVMOnly: return std::make_unique<EmitLLVMOnlyAction>();
case EmitCodeGenOnly: return std::make_unique<EmitCodeGenOnlyAction>();
case EmitObj: return std::make_unique<EmitObjAction>();
Expand Down
8 changes: 8 additions & 0 deletions clang/test/CIR/Lowering/hello.c
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() {}