clang 23.0.0git
GotoSolver.cpp
Go to the documentation of this file.
1//====- GotoSolver.cpp -----------------------------------===//
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#include "PassDetail.h"
11#include "llvm/ADT/SmallSet.h"
12#include "llvm/ADT/StringMap.h"
13#include "llvm/ADT/StringSet.h"
14#include "llvm/Support/TimeProfiler.h"
15#include <memory>
16
17using namespace mlir;
18using namespace cir;
19
20namespace mlir {
21#define GEN_PASS_DEF_GOTOSOLVER
22#include "clang/CIR/Dialect/Passes.h.inc"
23} // namespace mlir
24
25namespace {
26
27struct GotoSolverPass : public impl::GotoSolverBase<GotoSolverPass> {
28 GotoSolverPass() = default;
29 void runOnOperation() override;
30};
31
32static void process(cir::FuncOp func,
33 const llvm::StringSet<> &globalBlockAddrLabel) {
34 mlir::OpBuilder rewriter(func.getContext());
35 llvm::StringMap<Block *> labels;
37 llvm::SmallSet<StringRef, 4> blockAddrLabel;
38
39 func.getBody().walk([&](mlir::Operation *op) {
40 if (auto lab = dyn_cast<cir::LabelOp>(op)) {
41 labels.try_emplace(lab.getLabel(), lab->getBlock());
42 } else if (auto goTo = dyn_cast<cir::GotoOp>(op)) {
43 gotos.push_back(goTo);
44 } else if (auto blockAddr = dyn_cast<cir::BlockAddressOp>(op)) {
45 blockAddrLabel.insert(blockAddr.getBlockAddrInfo().getLabel());
46 }
47 });
48
49 for (auto &lab : labels) {
50 StringRef labelName = lab.getKey();
51 Block *block = lab.getValue();
52 // Keep labels whose address is taken either by a cir.block_address op in
53 // this function or by a block-address attribute used elsewhere (e.g. in a
54 // global initializer).
55 if (!blockAddrLabel.contains(labelName) &&
56 !globalBlockAddrLabel.contains(labelName)) {
57 // erase the LabelOp inside the block if safe
58 if (auto lab = dyn_cast<cir::LabelOp>(&block->front())) {
59 lab.erase();
60 }
61 }
62 }
63
64 for (auto goTo : gotos) {
65 mlir::OpBuilder::InsertionGuard guard(rewriter);
66 rewriter.setInsertionPoint(goTo);
67 Block *dest = labels[goTo.getLabel()];
68 cir::BrOp::create(rewriter, goTo.getLoc(), dest);
69 goTo.erase();
70 }
71}
72
73void GotoSolverPass::runOnOperation() {
74 llvm::TimeTraceScope scope("Goto Solver");
75
76 // Block addresses can also appear in attributes outside of any function body,
77 // such as global variable initializers. Collect, per target function, the
78 // labels referenced this way so their LabelOps are not erased below.
79 llvm::StringMap<llvm::StringSet<>> globalBlockAddrLabels;
80 getOperation()->walk([&](mlir::Operation *op) {
81 for (const mlir::NamedAttribute &namedAttr : op->getAttrs()) {
82 namedAttr.getValue().walk([&](cir::BlockAddrInfoAttr info) {
83 globalBlockAddrLabels[info.getFunc().getValue()].insert(
84 info.getLabel());
85 });
86 }
87 });
88
89 static const llvm::StringSet<> emptySet;
90 getOperation()->walk([&](cir::FuncOp func) {
91 auto it = globalBlockAddrLabels.find(func.getSymName());
92 process(func, it == globalBlockAddrLabels.end() ? emptySet : it->second);
93 });
94}
95
96} // namespace
97
98std::unique_ptr<Pass> mlir::createGotoSolverPass() {
99 return std::make_unique<GotoSolverPass>();
100}
std::unique_ptr< Pass > createGotoSolverPass()