clang 22.0.0git
HoistAllocas.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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 "PassDetail.h"
10#include "mlir/Dialect/Func/IR/FuncOps.h"
11#include "mlir/IR/PatternMatch.h"
12#include "mlir/Support/LogicalResult.h"
13#include "mlir/Transforms/DialectConversion.h"
14#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
18#include "llvm/Support/TimeProfiler.h"
19
20using namespace mlir;
21using namespace cir;
22
23namespace mlir {
24#define GEN_PASS_DEF_HOISTALLOCAS
25#include "clang/CIR/Dialect/Passes.h.inc"
26} // namespace mlir
27
28namespace {
29
30struct HoistAllocasPass : public impl::HoistAllocasBase<HoistAllocasPass> {
31
32 HoistAllocasPass() = default;
33 void runOnOperation() override;
34};
35
36static void process(mlir::ModuleOp mod, cir::FuncOp func) {
37 if (func.getRegion().empty())
38 return;
39
40 // Hoist all static allocas to the entry block.
41 mlir::Block &entryBlock = func.getRegion().front();
42 mlir::Operation *insertPoint = &*entryBlock.begin();
43
44 // Post-order is the default, but the code below requires it, so
45 // let's not depend on the default staying that way.
46 func.getBody().walk<mlir::WalkOrder::PostOrder>([&](cir::AllocaOp alloca) {
47 if (alloca->getBlock() == &entryBlock)
48 return;
49 // Don't hoist allocas with dynamic alloca size.
50 if (alloca.getDynAllocSize())
51 return;
52
53 // Hoist allocas into the entry block.
54
55 // Preserving the `const` attribute on hoisted allocas can cause LLVM to
56 // incorrectly introduce invariant group metadata in some circumstances.
57 // The incubator performs some analysis to determine whether the attribute
58 // can be preserved, but it only runs this analysis when optimizations are
59 // enabled. Until we start tracking the optimization level, we can just
60 // always remove the `const` attribute.
62 if (alloca.getConstant())
63 alloca.setConstant(false);
64
65 alloca->moveBefore(insertPoint);
66 });
67}
68
69void HoistAllocasPass::runOnOperation() {
70 llvm::TimeTraceScope scope("Hoist Allocas");
71 llvm::SmallVector<Operation *, 16> ops;
72
73 Operation *op = getOperation();
74 auto mod = mlir::dyn_cast<mlir::ModuleOp>(op);
75 if (!mod)
76 mod = op->getParentOfType<mlir::ModuleOp>();
77
78 // If we ever introduce nested cir.function ops, we'll need to make this
79 // walk in post-order and recurse into nested functions.
80 getOperation()->walk<mlir::WalkOrder::PreOrder>([&](cir::FuncOp op) {
81 process(mod, op);
82 return mlir::WalkResult::skip();
83 });
84}
85
86} // namespace
87
88std::unique_ptr<Pass> mlir::createHoistAllocasPass() {
89 return std::make_unique<HoistAllocasPass>();
90}
std::unique_ptr< Pass > createHoistAllocasPass()
static bool optInfoAttr()