//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "PassDetail.h" #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/IR/PatternMatch.h" #include "mlir/Support/LogicalResult.h" #include "mlir/Transforms/DialectConversion.h" #include "mlir/Transforms/GreedyPatternRewriteDriver.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/Passes.h" #include "clang/CIR/MissingFeatures.h" #include "llvm/Support/TimeProfiler.h" using namespace mlir; using namespace cir; namespace { struct HoistAllocasPass : public HoistAllocasBase { HoistAllocasPass() = default; void runOnOperation() override; }; static void process(mlir::ModuleOp mod, cir::FuncOp func) { if (func.getRegion().empty()) return; // Hoist all static allocas to the entry block. mlir::Block &entryBlock = func.getRegion().front(); mlir::Operation *insertPoint = &*entryBlock.begin(); // Post-order is the default, but the code below requires it, so // let's not depend on the default staying that way. func.getBody().walk([&](cir::AllocaOp alloca) { if (alloca->getBlock() == &entryBlock) return; // Don't hoist allocas with dynamic alloca size. assert(!cir::MissingFeatures::opAllocaDynAllocSize()); // Hoist allocas into the entry block. // Preserving the `const` attribute on hoisted allocas can cause LLVM to // incorrectly introduce invariant group metadata in some circumstances. // The incubator performs some analysis to determine whether the attribute // can be preserved, but it only runs this analysis when optimizations are // enabled. Until we start tracking the optimization level, we can just // always remove the `const` attribute. assert(!cir::MissingFeatures::optInfoAttr()); if (alloca.getConstant()) alloca.setConstant(false); alloca->moveBefore(insertPoint); }); } void HoistAllocasPass::runOnOperation() { llvm::TimeTraceScope scope("Hoist Allocas"); llvm::SmallVector ops; Operation *op = getOperation(); auto mod = mlir::dyn_cast(op); if (!mod) mod = op->getParentOfType(); // If we ever introduce nested cir.function ops, we'll need to make this // walk in post-order and recurse into nested functions. getOperation()->walk([&](cir::FuncOp op) { process(mod, op); return mlir::WalkResult::skip(); }); } } // namespace std::unique_ptr mlir::createHoistAllocasPass() { return std::make_unique(); }