1//===- LegalizeForExport.cpp - Prepare for translation to LLVM IR ---------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "mlir/Dialect/LLVMIR/Transforms/LegalizeForExport.h"
10
11#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
12#include "mlir/Dialect/LLVMIR/Transforms/DIExpressionLegalization.h"
13#include "mlir/IR/Block.h"
14#include "mlir/IR/Builders.h"
15#include "mlir/Pass/Pass.h"
16
17namespace mlir {
18namespace LLVM {
19#define GEN_PASS_DEF_LLVMLEGALIZEFOREXPORTPASS
20#include "mlir/Dialect/LLVMIR/Transforms/Passes.h.inc"
21} // namespace LLVM
22} // namespace mlir
23
24using namespace mlir;
25
26/// If the given block has the same successor with different arguments,
27/// introduce dummy successor blocks so that all successors of the given block
28/// are different.
29static void ensureDistinctSuccessors(Block &bb) {
30 // Early exit if the block cannot have successors.
31 if (bb.empty() || !bb.back().mightHaveTrait<OpTrait::IsTerminator>())
32 return;
33
34 auto *terminator = bb.getTerminator();
35
36 // Find repeated successors with arguments.
37 llvm::SmallDenseMap<Block *, SmallVector<int, 4>> successorPositions;
38 for (int i = 0, e = terminator->getNumSuccessors(); i < e; ++i) {
39 Block *successor = terminator->getSuccessor(index: i);
40 // Blocks with no arguments are safe even if they appear multiple times
41 // because they don't need PHI nodes.
42 if (successor->getNumArguments() == 0)
43 continue;
44 successorPositions[successor].push_back(Elt: i);
45 }
46
47 // If a successor appears for the second or more time in the terminator,
48 // create a new dummy block that unconditionally branches to the original
49 // destination, and retarget the terminator to branch to this new block.
50 // There is no need to pass arguments to the dummy block because it will be
51 // dominated by the original block and can therefore use any values defined in
52 // the original block.
53 OpBuilder builder(terminator->getContext());
54 for (const auto &successor : successorPositions) {
55 // Start from the second occurrence of a block in the successor list.
56 for (int position : llvm::drop_begin(RangeOrContainer: successor.second, N: 1)) {
57 Block *dummyBlock = builder.createBlock(parent: bb.getParent());
58 terminator->setSuccessor(block: dummyBlock, index: position);
59 for (BlockArgument arg : successor.first->getArguments())
60 dummyBlock->addArgument(type: arg.getType(), loc: arg.getLoc());
61 builder.create<LLVM::BrOp>(location: terminator->getLoc(),
62 args: dummyBlock->getArguments(), args: successor.first);
63 }
64 }
65}
66
67void mlir::LLVM::ensureDistinctSuccessors(Operation *op) {
68 op->walk(callback: [](Operation *nested) {
69 for (Region &region : llvm::make_early_inc_range(Range: nested->getRegions())) {
70 for (Block &block : llvm::make_early_inc_range(Range&: region)) {
71 ::ensureDistinctSuccessors(bb&: block);
72 }
73 }
74 });
75}
76
77namespace {
78struct LegalizeForExportPass
79 : public LLVM::impl::LLVMLegalizeForExportPassBase<LegalizeForExportPass> {
80 void runOnOperation() override {
81 LLVM::ensureDistinctSuccessors(op: getOperation());
82 LLVM::legalizeDIExpressionsRecursively(op: getOperation());
83 }
84};
85} // namespace
86

source code of mlir/lib/Dialect/LLVMIR/Transforms/LegalizeForExport.cpp