Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 6 additions & 0 deletions clang/include/clang/CIR/Dialect/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
add_subdirectory(IR)

set(LLVM_TARGET_DEFINITIONS Passes.td)
mlir_tablegen(Passes.h.inc -gen-pass-decls -name CIR)
mlir_tablegen(Passes.capi.h.inc -gen-pass-capi-header --prefix CIR)
mlir_tablegen(Passes.capi.cpp.inc -gen-pass-capi-impl --prefix CIR)
add_public_tablegen_target(MLIRCIRPassIncGen)
40 changes: 40 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,46 @@ def ScopeOp : CIR_Op<"scope", [
];
}

//===----------------------------------------------------------------------===//
// BrOp
//===----------------------------------------------------------------------===//

def BrOp : CIR_Op<"br",
[DeclareOpInterfaceMethods<BranchOpInterface, ["getSuccessorForOperands"]>,
Pure, Terminator]> {
let summary = "Unconditional branch";
let description = [{
The `cir.br` branches unconditionally to a block. Used to represent C/C++
goto's and general block branching.

Note that for source level `goto`'s crossing scope boundaries, those are
usually represented with the "symbolic" `cir.goto` operation.

Example:

```mlir
...
cir.br ^bb3
^bb3:
cir.return
```
}];

let builders = [
OpBuilder<(ins "mlir::Block *":$dest,
CArg<"mlir::ValueRange", "{}">:$destOperands), [{
$_state.addSuccessors(dest);
$_state.addOperands(destOperands);
}]>
];

let arguments = (ins Variadic<CIR_AnyType>:$destOperands);
let successors = (successor AnySuccessor:$dest);
let assemblyFormat = [{
$dest (`(` $destOperands^ `:` type($destOperands) `)`)? attr-dict
}];
}

//===----------------------------------------------------------------------===//
// GlobalOp
//===----------------------------------------------------------------------===//
Expand Down
39 changes: 39 additions & 0 deletions clang/include/clang/CIR/Dialect/Passes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//===- Passes.h - CIR pass entry points -------------------------*- C++ -*-===//
//
// 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 header file defines prototypes that expose pass constructors.
//
//===----------------------------------------------------------------------===//

#ifndef CLANG_CIR_DIALECT_PASSES_H
#define CLANG_CIR_DIALECT_PASSES_H

#include "mlir/Pass/Pass.h"

namespace clang {
class ASTContext;
}
namespace mlir {

std::unique_ptr<Pass> createCIRFlattenCFGPass();

void populateCIRPreLoweringPasses(mlir::OpPassManager &pm);

//===----------------------------------------------------------------------===//
// Registration
//===----------------------------------------------------------------------===//

void registerCIRDialectTranslation(mlir::MLIRContext &context);

/// Generate the code for registering passes.
#define GEN_PASS_REGISTRATION
#include "clang/CIR/Dialect/Passes.h.inc"

} // namespace mlir

#endif // CLANG_CIR_DIALECT_PASSES_H
28 changes: 28 additions & 0 deletions clang/include/clang/CIR/Dialect/Passes.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef CLANG_CIR_DIALECT_PASSES_TD
#define CLANG_CIR_DIALECT_PASSES_TD

include "mlir/Pass/PassBase.td"

def CIRFlattenCFG : Pass<"cir-flatten-cfg"> {
let summary = "Produces flatten CFG";
let description = [{
This pass transforms CIR by inlining all the nested regions. Thus,
the following condtions are true after the pass applied:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
the following condtions are true after the pass applied:
the following conditions are true after the pass applied:

- there are no nested regions in any function body
- all the blocks in a function belong to the parent region
In other words, this pass removes such CIR operations like IfOp, LoopOp,
ScopeOp and etc. and produces a flat CIR.
}];
let constructor = "mlir::createCIRFlattenCFGPass()";
let dependentDialects = ["cir::CIRDialect"];
}

#endif // CLANG_CIR_DIALECT_PASSES_TD
1 change: 1 addition & 0 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ struct MissingFeatures {
static bool objCLifetime() { return false; }
static bool emitNullabilityCheck() { return false; }
static bool astVarDeclInterface() { return false; }
static bool stackSaveOp() { return false; }
};

} // namespace cir
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CIR/Dialect/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
add_subdirectory(IR)
add_subdirectory(Transforms)
13 changes: 13 additions & 0 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,19 @@ LogicalResult cir::ScopeOp::verify() {
return success();
}

//===----------------------------------------------------------------------===//
// BrOp
//===----------------------------------------------------------------------===//

mlir::SuccessorOperands cir::BrOp::getSuccessorOperands(unsigned index) {
assert(index == 0 && "invalid successor index");
return mlir::SuccessorOperands(getDestOperandsMutable());
}

Block *cir::BrOp::getSuccessorForOperands(ArrayRef<Attribute>) {
return getDest();
}

//===----------------------------------------------------------------------===//
// GlobalOp
//===----------------------------------------------------------------------===//
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CIR/Dialect/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ add_clang_library(MLIRCIR

LINK_LIBS PUBLIC
MLIRIR
MLIRCIRInterfaces
MLIRDLTIDialect
MLIRDataLayoutInterfaces
MLIRFuncDialect
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/CIR/Dialect/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
add_clang_library(MLIRCIRTransforms
FlattenCFG.cpp

DEPENDS
MLIRCIRPassIncGen

LINK_LIBS PUBLIC
clangAST
clangBasic

MLIRAnalysis
MLIRIR
MLIRPass
MLIRTransformUtils

MLIRCIR
MLIRCIRInterfaces
)
117 changes: 117 additions & 0 deletions clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
//===----------------------------------------------------------------------===//
//
// 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 inlines CIR operations regions into the parent
// function region.
//
//===----------------------------------------------------------------------===//

#include "PassDetail.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/Support/LogicalResult.h"
#include "mlir/Transforms/DialectConversion.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 {

struct CIRFlattenCFGPass : public CIRFlattenCFGBase<CIRFlattenCFGPass> {

CIRFlattenCFGPass() = default;
void runOnOperation() override;
};

class CIRScopeOpFlattening : public mlir::OpRewritePattern<cir::ScopeOp> {
public:
using OpRewritePattern<cir::ScopeOp>::OpRewritePattern;

mlir::LogicalResult
matchAndRewrite(cir::ScopeOp scopeOp,
mlir::PatternRewriter &rewriter) const override {
mlir::OpBuilder::InsertionGuard guard(rewriter);
mlir::Location loc = scopeOp.getLoc();

// Empty scope: just remove it.
// TODO: Remove this logic once CIR uses MLIR infrastructure to remove
// trivially dead operations. MLIR canonicalizer is too aggressive and we
// need to either (a) make sure all our ops model all side-effects and/or
// (b) have more options in the canonicalizer in MLIR to temper
// aggressiveness level.
if (scopeOp.isEmpty()) {
rewriter.eraseOp(scopeOp);
return mlir::success();
}

// Split the current block before the ScopeOp to create the inlining
// point.
mlir::Block *currentBlock = rewriter.getInsertionBlock();
mlir::Block *continueBlock =
rewriter.splitBlock(currentBlock, rewriter.getInsertionPoint());
if (scopeOp.getNumResults() > 0)
continueBlock->addArguments(scopeOp.getResultTypes(), loc);

// Inline body region.
mlir::Block *beforeBody = &scopeOp.getScopeRegion().front();
mlir::Block *afterBody = &scopeOp.getScopeRegion().back();
rewriter.inlineRegionBefore(scopeOp.getScopeRegion(), continueBlock);

// Save stack and then branch into the body of the region.
rewriter.setInsertionPointToEnd(currentBlock);
assert(!cir::MissingFeatures::stackSaveOp());
rewriter.create<cir::BrOp>(loc, mlir::ValueRange(), beforeBody);

// Replace the scopeop return with a branch that jumps out of the body.
// Stack restore before leaving the body region.
rewriter.setInsertionPointToEnd(afterBody);
if (auto yieldOp = dyn_cast<cir::YieldOp>(afterBody->getTerminator())) {
rewriter.replaceOpWithNewOp<cir::BrOp>(yieldOp, yieldOp.getArgs(),
continueBlock);
}

// Replace the op with values return from the body region.
rewriter.replaceOp(scopeOp, continueBlock->getArguments());

return mlir::success();
}
};

void populateFlattenCFGPatterns(RewritePatternSet &patterns) {
patterns.add<CIRScopeOpFlattening>(patterns.getContext());
}

void CIRFlattenCFGPass::runOnOperation() {
RewritePatternSet patterns(&getContext());
populateFlattenCFGPatterns(patterns);

// Collect operations to apply patterns.
llvm::SmallVector<Operation *, 16> ops;
getOperation()->walk<mlir::WalkOrder::PostOrder>([&](Operation *op) {
if (isa<ScopeOp>(op))
ops.push_back(op);
});

// Apply patterns.
if (applyOpPatternsGreedily(ops, std::move(patterns)).failed())
signalPassFailure();
}

} // namespace

namespace mlir {

std::unique_ptr<Pass> createCIRFlattenCFGPass() {
return std::make_unique<CIRFlattenCFGPass>();
}

} // namespace mlir
29 changes: 29 additions & 0 deletions clang/lib/CIR/Dialect/Transforms/PassDetail.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef CIR_DIALECT_TRANSFORMS_PASSDETAIL_H
#define CIR_DIALECT_TRANSFORMS_PASSDETAIL_H

#include "mlir/IR/Dialect.h"
#include "mlir/Pass/Pass.h"

namespace cir {
class CIRDialect;
} // namespace cir

namespace mlir {
// Forward declaration from Dialect.h
template <typename ConcreteDialect>
void registerDialect(DialectRegistry &registry);

#define GEN_PASS_CLASSES
#include "clang/CIR/Dialect/Passes.h.inc"

} // namespace mlir

#endif // CIR_DIALECT_TRANSFORMS_PASSDETAIL_H
24 changes: 24 additions & 0 deletions clang/lib/CIR/Lowering/CIRPasses.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// 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 machinery for any CIR <-> CIR passes used by clang.
//
//===----------------------------------------------------------------------===//

// #include "clang/AST/ASTContext.h"
#include "clang/CIR/Dialect/Passes.h"

#include "mlir/Pass/PassManager.h"

namespace mlir {

void populateCIRPreLoweringPasses(OpPassManager &pm) {
pm.addPass(createCIRFlattenCFGPass());
}

} // namespace mlir
19 changes: 19 additions & 0 deletions clang/lib/CIR/Lowering/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1 +1,20 @@
set(LLVM_LINK_COMPONENTS
Core
Support
)

get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)

add_clang_library(clangCIRLoweringCommon
CIRPasses.cpp

LINK_LIBS
clangCIR
${dialect_libs}
MLIRCIR
MLIRCIRTransforms
MLIRTransforms
MLIRSupport
)

add_subdirectory(DirectToLLVM)
4 changes: 3 additions & 1 deletion clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)

add_clang_library(clangCIRLoweringDirectToLLVM
LowerToLLVM.cpp
LowerToLLVMIR.cpp

DEPENDS
MLIRCIREnumsGen
MLIRCIROpsIncGen
MLIRCIROpInterfacesIncGen

LINK_LIBS
MLIRIR
clangCIRLoweringCommon
${dialect_libs}
MLIRCIR
MLIRBuiltinToLLVMIRTranslation
MLIRLLVMToLLVMIRTranslation
MLIRIR
)
Loading