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