aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenModule.cpp8
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenModule.h2
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenerator.cpp2
-rw-r--r--clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp145
-rw-r--r--clang/lib/CIR/Dialect/Transforms/CMakeLists.txt1
-rw-r--r--clang/lib/CIR/FrontendAction/CIRGenAction.cpp29
-rw-r--r--clang/lib/CIR/FrontendAction/CMakeLists.txt2
-rw-r--r--clang/lib/CIR/Lowering/CIRPasses.cpp21
-rw-r--r--clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp2
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp9
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp8
-rw-r--r--clang/lib/FrontendTool/CMakeLists.txt9
-rw-r--r--clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp20
13 files changed, 256 insertions, 2 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 0e3e15c..36bfc2c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -23,6 +23,7 @@
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Location.h"
#include "mlir/IR/MLIRContext.h"
+#include "mlir/IR/Verifier.h"
using namespace clang;
using namespace clang::CIRGen;
@@ -488,6 +489,13 @@ mlir::Type CIRGenModule::convertType(QualType type) {
return genTypes.convertType(type);
}
+bool CIRGenModule::verifyModule() const {
+ // Verify the module after we have finished constructing it, this will
+ // check the structural properties of the IR and invoke any specific
+ // verifiers we have on the CIR operations.
+ return mlir::verify(theModule).succeeded();
+}
+
DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
llvm::StringRef feature) {
unsigned diagID = diags.getCustomDiagID(
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 2a798f4..734cafa 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -91,6 +91,8 @@ public:
void emitTopLevelDecl(clang::Decl *decl);
+ bool verifyModule() const;
+
/// Return the address of the given function. If funcType is non-null, then
/// this function will use the specified type if it has to create it.
// TODO: this is a bit weird as `GetAddr` given we give back a FuncOp?
diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp
index 6fa31ab..33f0c29 100644
--- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp
@@ -40,6 +40,8 @@ void CIRGenerator::Initialize(ASTContext &astContext) {
*mlirContext.get(), astContext, codeGenOpts, diags);
}
+bool CIRGenerator::verifyModule() const { return cgm->verifyModule(); }
+
mlir::ModuleOp CIRGenerator::getModule() const { return cgm->getModule(); }
bool CIRGenerator::HandleTopLevelDecl(DeclGroupRef group) {
diff --git a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp
new file mode 100644
index 0000000..d32691d
--- /dev/null
+++ b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp
@@ -0,0 +1,145 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 pass that canonicalizes CIR operations, eliminating
+// redundant branches, empty scopes, and other unnecessary operations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PassDetail.h"
+#include "mlir/Dialect/Func/IR/FuncOps.h"
+#include "mlir/IR/Block.h"
+#include "mlir/IR/Operation.h"
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/IR/Region.h"
+#include "mlir/Support/LogicalResult.h"
+#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/Passes.h"
+#include "clang/CIR/MissingFeatures.h"
+
+using namespace mlir;
+using namespace cir;
+
+namespace {
+
+/// Removes branches between two blocks if it is the only branch.
+///
+/// From:
+/// ^bb0:
+/// cir.br ^bb1
+/// ^bb1: // pred: ^bb0
+/// cir.return
+///
+/// To:
+/// ^bb0:
+/// cir.return
+struct RemoveRedundantBranches : public OpRewritePattern<BrOp> {
+ using OpRewritePattern<BrOp>::OpRewritePattern;
+
+ LogicalResult matchAndRewrite(BrOp op,
+ PatternRewriter &rewriter) const final {
+ Block *block = op.getOperation()->getBlock();
+ Block *dest = op.getDest();
+
+ assert(!cir::MissingFeatures::labelOp());
+
+ // Single edge between blocks: merge it.
+ if (block->getNumSuccessors() == 1 &&
+ dest->getSinglePredecessor() == block) {
+ rewriter.eraseOp(op);
+ rewriter.mergeBlocks(dest, block);
+ return success();
+ }
+
+ return failure();
+ }
+};
+
+struct RemoveEmptyScope
+ : public OpRewritePattern<ScopeOp>::SplitMatchAndRewrite {
+ using SplitMatchAndRewrite::SplitMatchAndRewrite;
+
+ LogicalResult match(ScopeOp op) const final {
+ // TODO: Remove this logic once CIR uses MLIR infrastructure to remove
+ // trivially dead operations
+ if (op.isEmpty())
+ return success();
+
+ Region &region = op.getScopeRegion();
+ if (region.getBlocks().front().getOperations().size() == 1)
+ return success(isa<YieldOp>(region.getBlocks().front().front()));
+
+ return failure();
+ }
+
+ void rewrite(ScopeOp op, PatternRewriter &rewriter) const final {
+ rewriter.eraseOp(op);
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// CIRCanonicalizePass
+//===----------------------------------------------------------------------===//
+
+struct CIRCanonicalizePass : public CIRCanonicalizeBase<CIRCanonicalizePass> {
+ using CIRCanonicalizeBase::CIRCanonicalizeBase;
+
+ // The same operation rewriting done here could have been performed
+ // by CanonicalizerPass (adding hasCanonicalizer for target Ops and
+ // implementing the same from above in CIRDialects.cpp). However, it's
+ // currently too aggressive for static analysis purposes, since it might
+ // remove things where a diagnostic can be generated.
+ //
+ // FIXME: perhaps we can add one more mode to GreedyRewriteConfig to
+ // disable this behavior.
+ void runOnOperation() override;
+};
+
+void populateCIRCanonicalizePatterns(RewritePatternSet &patterns) {
+ // clang-format off
+ patterns.add<
+ RemoveRedundantBranches,
+ RemoveEmptyScope
+ >(patterns.getContext());
+ // clang-format on
+}
+
+void CIRCanonicalizePass::runOnOperation() {
+ // Collect rewrite patterns.
+ RewritePatternSet patterns(&getContext());
+ populateCIRCanonicalizePatterns(patterns);
+
+ // Collect operations to apply patterns.
+ llvm::SmallVector<Operation *, 16> ops;
+ getOperation()->walk([&](Operation *op) {
+ assert(!cir::MissingFeatures::brCondOp());
+ assert(!cir::MissingFeatures::switchOp());
+ assert(!cir::MissingFeatures::tryOp());
+ assert(!cir::MissingFeatures::unaryOp());
+ assert(!cir::MissingFeatures::selectOp());
+ assert(!cir::MissingFeatures::complexCreateOp());
+ assert(!cir::MissingFeatures::complexRealOp());
+ assert(!cir::MissingFeatures::complexImagOp());
+ assert(!cir::MissingFeatures::callOp());
+ // CastOp here is to perform a manual `fold` in
+ // applyOpPatternsGreedily
+ if (isa<BrOp, ScopeOp, CastOp>(op))
+ ops.push_back(op);
+ });
+
+ // Apply patterns.
+ if (applyOpPatternsGreedily(ops, std::move(patterns)).failed())
+ signalPassFailure();
+}
+
+} // namespace
+
+std::unique_ptr<Pass> mlir::createCIRCanonicalizePass() {
+ return std::make_unique<CIRCanonicalizePass>();
+}
diff --git a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
index aa27074..648666d 100644
--- a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
+++ b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
@@ -1,4 +1,5 @@
add_clang_library(MLIRCIRTransforms
+ CIRCanonicalize.cpp
FlattenCFG.cpp
DEPENDS
diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
index 0f686a3..a32e6a7 100644
--- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
+++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
@@ -9,7 +9,9 @@
#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"
@@ -59,6 +61,7 @@ class CIRGenConsumer : public clang::ASTConsumer {
ASTContext *Context{nullptr};
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
std::unique_ptr<CIRGenerator> Gen;
+ const FrontendOptions &FEOptions;
public:
CIRGenConsumer(CIRGenAction::OutputType Action, CompilerInstance &CI,
@@ -66,7 +69,8 @@ public:
: Action(Action), CI(CI), OutputStream(std::move(OS)),
FS(&CI.getVirtualFileSystem()),
Gen(std::make_unique<CIRGenerator>(CI.getDiagnostics(), std::move(FS),
- CI.getCodeGenOpts())) {}
+ CI.getCodeGenOpts())),
+ FEOptions(CI.getFrontendOpts()) {}
void Initialize(ASTContext &Ctx) override {
assert(!Context && "initialized multiple times");
@@ -81,7 +85,30 @@ public:
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) {
diff --git a/clang/lib/CIR/FrontendAction/CMakeLists.txt b/clang/lib/CIR/FrontendAction/CMakeLists.txt
index 1ebac07..50d6ea7 100644
--- a/clang/lib/CIR/FrontendAction/CMakeLists.txt
+++ b/clang/lib/CIR/FrontendAction/CMakeLists.txt
@@ -15,8 +15,10 @@ add_clang_library(clangCIRFrontendAction
LINK_LIBS
clangAST
+ clangBasic
clangFrontend
clangCIR
+ clangCIRLoweringCommon
clangCIRLoweringDirectToLLVM
clangCodeGen
MLIRCIR
diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp b/clang/lib/CIR/Lowering/CIRPasses.cpp
index 235acbf..1616ac6 100644
--- a/clang/lib/CIR/Lowering/CIRPasses.cpp
+++ b/clang/lib/CIR/Lowering/CIRPasses.cpp
@@ -11,9 +11,28 @@
//===----------------------------------------------------------------------===//
// #include "clang/AST/ASTContext.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/Pass/PassManager.h"
#include "clang/CIR/Dialect/Passes.h"
+#include "llvm/Support/TimeProfiler.h"
-#include "mlir/Pass/PassManager.h"
+namespace cir {
+mlir::LogicalResult runCIRToCIRPasses(mlir::ModuleOp theModule,
+ mlir::MLIRContext &mlirContext,
+ clang::ASTContext &astContext,
+ bool enableVerifier) {
+
+ llvm::TimeTraceScope scope("CIR To CIR Passes");
+
+ mlir::PassManager pm(&mlirContext);
+ pm.addPass(mlir::createCIRCanonicalizePass());
+
+ pm.enableVerifier(enableVerifier);
+ (void)mlir::applyPassManagerCLOptions(pm);
+ return pm.run(theModule);
+}
+
+} // namespace cir
namespace mlir {
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 93d83f2..db94cf5 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1115,6 +1115,8 @@ lowerDirectlyFromCIRToLLVMIR(mlir::ModuleOp mlirModule, LLVMContext &llvmCtx) {
mlir::PassManager pm(mlirCtx);
populateCIRToLLVMPasses(pm);
+ (void)mlir::applyPassManagerCLOptions(pm);
+
if (mlir::failed(pm.run(mlirModule))) {
// FIXME: Handle any errors where they occurs and return a nullptr here.
report_fatal_error(
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 1012128..fa4fb41 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5520,6 +5520,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_Wa_COMMA,
options::OPT_Xassembler,
options::OPT_mllvm,
+ options::OPT_mmlir,
};
for (const auto &A : Args)
if (llvm::is_contained(kBitcodeOptionIgnorelist, A->getOption().getID()))
@@ -7778,6 +7779,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// features enabled through -Xclang -target-feature flags.
SanitizeArgs.addArgs(TC, Args, CmdArgs, InputType);
+#if CLANG_ENABLE_CIR
+ // Forward -mmlir arguments to to the MLIR option parser.
+ for (const Arg *A : Args.filtered(options::OPT_mmlir)) {
+ A->claim();
+ A->render(Args, CmdArgs);
+ }
+#endif // CLANG_ENABLE_CIR
+
// With -save-temps, we want to save the unoptimized bitcode output from the
// CompileJobAction, use -disable-llvm-passes to get pristine IR generated
// by the frontend.
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index e708bee..b2d8d12 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3105,6 +3105,14 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
if (Args.hasArg(OPT_fclangir) || Args.hasArg(OPT_emit_cir))
Opts.UseClangIRPipeline = true;
+#if CLANG_ENABLE_CIR
+ if (Args.hasArg(OPT_clangir_disable_passes))
+ Opts.ClangIRDisablePasses = true;
+
+ if (Args.hasArg(OPT_clangir_disable_verifier))
+ Opts.ClangIRDisableCIRVerifier = true;
+#endif // CLANG_ENABLE_CIR
+
if (Args.hasArg(OPT_aux_target_cpu))
Opts.AuxTargetCPU = std::string(Args.getLastArgValue(OPT_aux_target_cpu));
if (Args.hasArg(OPT_aux_target_feature))
diff --git a/clang/lib/FrontendTool/CMakeLists.txt b/clang/lib/FrontendTool/CMakeLists.txt
index 7c83086..061e54c 100644
--- a/clang/lib/FrontendTool/CMakeLists.txt
+++ b/clang/lib/FrontendTool/CMakeLists.txt
@@ -20,8 +20,17 @@ if(CLANG_ENABLE_CIR)
)
list(APPEND link_libs
clangCIRFrontendAction
+ MLIRCIRTransforms
MLIRIR
+ MLIRPass
)
+ list(APPEND deps
+ MLIRBuiltinLocationAttributesIncGen
+ MLIRBuiltinTypeInterfacesIncGen
+ )
+
+ include_directories(${LLVM_MAIN_SRC_DIR}/../mlir/include)
+ include_directories(${CMAKE_BINARY_DIR}/tools/mlir/include)
endif()
if(CLANG_ENABLE_STATIC_ANALYZER)
diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index bb3bb0a..6fc587f 100644
--- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -32,6 +32,10 @@
#include "llvm/Support/ErrorHandling.h"
#if CLANG_ENABLE_CIR
+#include "mlir/IR/AsmState.h"
+#include "mlir/IR/MLIRContext.h"
+#include "mlir/Pass/PassManager.h"
+#include "clang/CIR/Dialect/Passes.h"
#include "clang/CIR/FrontendAction/CIRGenAction.h"
#endif
@@ -270,6 +274,22 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
}
#endif
+#if CLANG_ENABLE_CIR
+ if (!Clang->getFrontendOpts().MLIRArgs.empty()) {
+ mlir::registerCIRPasses();
+ mlir::registerMLIRContextCLOptions();
+ mlir::registerPassManagerCLOptions();
+ mlir::registerAsmPrinterCLOptions();
+ unsigned NumArgs = Clang->getFrontendOpts().MLIRArgs.size();
+ auto Args = std::make_unique<const char *[]>(NumArgs + 2);
+ Args[0] = "clang (MLIR option parsing)";
+ for (unsigned i = 0; i != NumArgs; ++i)
+ Args[i + 1] = Clang->getFrontendOpts().MLIRArgs[i].c_str();
+ Args[NumArgs + 1] = nullptr;
+ llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
+ }
+#endif
+
// If there were errors in processing arguments, don't do anything else.
if (Clang->getDiagnostics().hasErrorOccurred())
return false;