xref: /freebsd/contrib/llvm-project/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric 
9*700637cbSDimitry Andric #include "PassDetail.h"
10*700637cbSDimitry Andric #include "mlir/Dialect/Func/IR/FuncOps.h"
11*700637cbSDimitry Andric #include "mlir/IR/PatternMatch.h"
12*700637cbSDimitry Andric #include "mlir/Support/LogicalResult.h"
13*700637cbSDimitry Andric #include "mlir/Transforms/DialectConversion.h"
14*700637cbSDimitry Andric #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
15*700637cbSDimitry Andric #include "clang/CIR/Dialect/IR/CIRDialect.h"
16*700637cbSDimitry Andric #include "clang/CIR/Dialect/Passes.h"
17*700637cbSDimitry Andric #include "clang/CIR/MissingFeatures.h"
18*700637cbSDimitry Andric #include "llvm/Support/TimeProfiler.h"
19*700637cbSDimitry Andric 
20*700637cbSDimitry Andric using namespace mlir;
21*700637cbSDimitry Andric using namespace cir;
22*700637cbSDimitry Andric 
23*700637cbSDimitry Andric namespace {
24*700637cbSDimitry Andric 
25*700637cbSDimitry Andric struct HoistAllocasPass : public HoistAllocasBase<HoistAllocasPass> {
26*700637cbSDimitry Andric 
27*700637cbSDimitry Andric   HoistAllocasPass() = default;
28*700637cbSDimitry Andric   void runOnOperation() override;
29*700637cbSDimitry Andric };
30*700637cbSDimitry Andric 
process(mlir::ModuleOp mod,cir::FuncOp func)31*700637cbSDimitry Andric static void process(mlir::ModuleOp mod, cir::FuncOp func) {
32*700637cbSDimitry Andric   if (func.getRegion().empty())
33*700637cbSDimitry Andric     return;
34*700637cbSDimitry Andric 
35*700637cbSDimitry Andric   // Hoist all static allocas to the entry block.
36*700637cbSDimitry Andric   mlir::Block &entryBlock = func.getRegion().front();
37*700637cbSDimitry Andric   mlir::Operation *insertPoint = &*entryBlock.begin();
38*700637cbSDimitry Andric 
39*700637cbSDimitry Andric   // Post-order is the default, but the code below requires it, so
40*700637cbSDimitry Andric   // let's not depend on the default staying that way.
41*700637cbSDimitry Andric   func.getBody().walk<mlir::WalkOrder::PostOrder>([&](cir::AllocaOp alloca) {
42*700637cbSDimitry Andric     if (alloca->getBlock() == &entryBlock)
43*700637cbSDimitry Andric       return;
44*700637cbSDimitry Andric     // Don't hoist allocas with dynamic alloca size.
45*700637cbSDimitry Andric     assert(!cir::MissingFeatures::opAllocaDynAllocSize());
46*700637cbSDimitry Andric 
47*700637cbSDimitry Andric     // Hoist allocas into the entry block.
48*700637cbSDimitry Andric 
49*700637cbSDimitry Andric     // Preserving the `const` attribute on hoisted allocas can cause LLVM to
50*700637cbSDimitry Andric     // incorrectly introduce invariant group metadata in some circumstances.
51*700637cbSDimitry Andric     // The incubator performs some analysis to determine whether the attribute
52*700637cbSDimitry Andric     // can be preserved, but it only runs this analysis when optimizations are
53*700637cbSDimitry Andric     // enabled. Until we start tracking the optimization level, we can just
54*700637cbSDimitry Andric     // always remove the `const` attribute.
55*700637cbSDimitry Andric     assert(!cir::MissingFeatures::optInfoAttr());
56*700637cbSDimitry Andric     if (alloca.getConstant())
57*700637cbSDimitry Andric       alloca.setConstant(false);
58*700637cbSDimitry Andric 
59*700637cbSDimitry Andric     alloca->moveBefore(insertPoint);
60*700637cbSDimitry Andric   });
61*700637cbSDimitry Andric }
62*700637cbSDimitry Andric 
runOnOperation()63*700637cbSDimitry Andric void HoistAllocasPass::runOnOperation() {
64*700637cbSDimitry Andric   llvm::TimeTraceScope scope("Hoist Allocas");
65*700637cbSDimitry Andric   llvm::SmallVector<Operation *, 16> ops;
66*700637cbSDimitry Andric 
67*700637cbSDimitry Andric   Operation *op = getOperation();
68*700637cbSDimitry Andric   auto mod = mlir::dyn_cast<mlir::ModuleOp>(op);
69*700637cbSDimitry Andric   if (!mod)
70*700637cbSDimitry Andric     mod = op->getParentOfType<mlir::ModuleOp>();
71*700637cbSDimitry Andric 
72*700637cbSDimitry Andric   // If we ever introduce nested cir.function ops, we'll need to make this
73*700637cbSDimitry Andric   // walk in post-order and recurse into nested functions.
74*700637cbSDimitry Andric   getOperation()->walk<mlir::WalkOrder::PreOrder>([&](cir::FuncOp op) {
75*700637cbSDimitry Andric     process(mod, op);
76*700637cbSDimitry Andric     return mlir::WalkResult::skip();
77*700637cbSDimitry Andric   });
78*700637cbSDimitry Andric }
79*700637cbSDimitry Andric 
80*700637cbSDimitry Andric } // namespace
81*700637cbSDimitry Andric 
createHoistAllocasPass()82*700637cbSDimitry Andric std::unique_ptr<Pass> mlir::createHoistAllocasPass() {
83*700637cbSDimitry Andric   return std::make_unique<HoistAllocasPass>();
84*700637cbSDimitry Andric }
85