CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
185 lines
7.0 KiB
C++
185 lines
7.0 KiB
C++
//===- ACCRecipeBufferization.cpp -----------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Bufferize OpenACC recipes that yield fir.box<T> to operate on
|
|
// fir.ref<fir.box<T>> and update uses accordingly.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "flang/Optimizer/Dialect/FIROps.h"
|
|
#include "flang/Optimizer/OpenACC/Passes.h"
|
|
#include "mlir/Dialect/OpenACC/OpenACC.h"
|
|
#include "mlir/IR/Block.h"
|
|
#include "mlir/IR/Builders.h"
|
|
#include "mlir/IR/BuiltinOps.h"
|
|
#include "mlir/IR/SymbolTable.h"
|
|
#include "mlir/IR/Value.h"
|
|
#include "mlir/IR/Visitors.h"
|
|
#include "llvm/ADT/TypeSwitch.h"
|
|
|
|
namespace fir::acc {
|
|
#define GEN_PASS_DEF_ACCRECIPEBUFFERIZATION
|
|
#include "flang/Optimizer/OpenACC/Passes.h.inc"
|
|
} // namespace fir::acc
|
|
|
|
namespace {
|
|
|
|
class BufferizeInterface {
|
|
public:
|
|
static std::optional<mlir::Type> mustBufferize(mlir::Type recipeType) {
|
|
if (auto boxTy = llvm::dyn_cast<fir::BaseBoxType>(recipeType))
|
|
return fir::ReferenceType::get(boxTy);
|
|
return std::nullopt;
|
|
}
|
|
|
|
static mlir::Operation *load(mlir::OpBuilder &builder, mlir::Location loc,
|
|
mlir::Value value) {
|
|
return fir::LoadOp::create(builder, loc, value);
|
|
}
|
|
|
|
static mlir::Value placeInMemory(mlir::OpBuilder &builder, mlir::Location loc,
|
|
mlir::Value value) {
|
|
auto alloca = fir::AllocaOp::create(builder, loc, value.getType());
|
|
fir::StoreOp::create(builder, loc, value, alloca);
|
|
return alloca;
|
|
}
|
|
};
|
|
|
|
static void bufferizeRegionArgsAndYields(mlir::Region ®ion,
|
|
mlir::Location loc, mlir::Type oldType,
|
|
mlir::Type newType) {
|
|
if (region.empty())
|
|
return;
|
|
|
|
mlir::OpBuilder builder(®ion);
|
|
for (mlir::BlockArgument arg : region.getArguments()) {
|
|
if (arg.getType() == oldType) {
|
|
arg.setType(newType);
|
|
if (!arg.use_empty()) {
|
|
mlir::Operation *loadOp = BufferizeInterface::load(builder, loc, arg);
|
|
arg.replaceAllUsesExcept(loadOp->getResult(0), loadOp);
|
|
}
|
|
}
|
|
}
|
|
if (auto yield =
|
|
llvm::dyn_cast<mlir::acc::YieldOp>(region.back().getTerminator())) {
|
|
llvm::SmallVector<mlir::Value> newOperands;
|
|
newOperands.reserve(yield.getNumOperands());
|
|
bool changed = false;
|
|
for (mlir::Value oldYieldArg : yield.getOperands()) {
|
|
if (oldYieldArg.getType() == oldType) {
|
|
builder.setInsertionPoint(yield);
|
|
mlir::Value alloca =
|
|
BufferizeInterface::placeInMemory(builder, loc, oldYieldArg);
|
|
newOperands.push_back(alloca);
|
|
changed = true;
|
|
} else {
|
|
newOperands.push_back(oldYieldArg);
|
|
}
|
|
}
|
|
if (changed)
|
|
yield->setOperands(newOperands);
|
|
}
|
|
}
|
|
|
|
template <typename OpTy>
|
|
static void updateRecipeUse(mlir::ValueRange operands,
|
|
llvm::StringRef recipeSymName,
|
|
mlir::Operation *computeOp) {
|
|
for (auto operand : operands) {
|
|
auto op = operand.getDefiningOp<OpTy>();
|
|
if (!op || !op.getRecipe().has_value() ||
|
|
op.getRecipeAttr().getLeafReference() != recipeSymName)
|
|
continue;
|
|
|
|
mlir::Location loc = op->getLoc();
|
|
|
|
mlir::OpBuilder builder(op);
|
|
builder.setInsertionPointAfterValue(op.getVar());
|
|
mlir::Value alloca =
|
|
BufferizeInterface::placeInMemory(builder, loc, op.getVar());
|
|
op.getVarMutable().assign(alloca);
|
|
op.getAccVar().setType(alloca.getType());
|
|
|
|
mlir::Value oldRes = op.getAccVar();
|
|
llvm::SmallVector<mlir::Operation *> users(oldRes.getUsers().begin(),
|
|
oldRes.getUsers().end());
|
|
for (mlir::Operation *useOp : users) {
|
|
if (useOp == computeOp)
|
|
continue;
|
|
builder.setInsertionPoint(useOp);
|
|
mlir::Operation *load = BufferizeInterface::load(builder, loc, oldRes);
|
|
useOp->replaceUsesOfWith(oldRes, load->getResult(0));
|
|
}
|
|
}
|
|
}
|
|
|
|
class ACCRecipeBufferization
|
|
: public fir::acc::impl::ACCRecipeBufferizationBase<
|
|
ACCRecipeBufferization> {
|
|
public:
|
|
void runOnOperation() override {
|
|
mlir::ModuleOp module = getOperation();
|
|
|
|
llvm::SmallVector<llvm::StringRef> recipeNames;
|
|
module.walk([&](mlir::Operation *recipe) {
|
|
llvm::TypeSwitch<mlir::Operation *, void>(recipe)
|
|
.Case<mlir::acc::PrivateRecipeOp, mlir::acc::FirstprivateRecipeOp,
|
|
mlir::acc::ReductionRecipeOp>([&](auto recipe) {
|
|
mlir::Type oldType = recipe.getType();
|
|
auto bufferizedType =
|
|
BufferizeInterface::mustBufferize(recipe.getType());
|
|
if (!bufferizedType)
|
|
return;
|
|
recipe.setTypeAttr(mlir::TypeAttr::get(*bufferizedType));
|
|
mlir::Location loc = recipe.getLoc();
|
|
using RecipeOp = decltype(recipe);
|
|
bufferizeRegionArgsAndYields(recipe.getInitRegion(), loc, oldType,
|
|
*bufferizedType);
|
|
if constexpr (std::is_same_v<RecipeOp,
|
|
mlir::acc::FirstprivateRecipeOp>)
|
|
bufferizeRegionArgsAndYields(recipe.getCopyRegion(), loc, oldType,
|
|
*bufferizedType);
|
|
if constexpr (std::is_same_v<RecipeOp,
|
|
mlir::acc::ReductionRecipeOp>)
|
|
bufferizeRegionArgsAndYields(recipe.getCombinerRegion(), loc,
|
|
oldType, *bufferizedType);
|
|
bufferizeRegionArgsAndYields(recipe.getDestroyRegion(), loc,
|
|
oldType, *bufferizedType);
|
|
recipeNames.push_back(recipe.getSymName());
|
|
});
|
|
});
|
|
if (recipeNames.empty())
|
|
return;
|
|
|
|
module.walk([&](mlir::Operation *op) {
|
|
llvm::TypeSwitch<mlir::Operation *, void>(op)
|
|
.Case<mlir::acc::LoopOp, mlir::acc::ParallelOp, mlir::acc::SerialOp>(
|
|
[&](auto computeOp) {
|
|
for (llvm::StringRef recipeName : recipeNames) {
|
|
if (!computeOp.getPrivateOperands().empty())
|
|
updateRecipeUse<mlir::acc::PrivateOp>(
|
|
computeOp.getPrivateOperands(), recipeName, op);
|
|
if (!computeOp.getFirstprivateOperands().empty())
|
|
updateRecipeUse<mlir::acc::FirstprivateOp>(
|
|
computeOp.getFirstprivateOperands(), recipeName, op);
|
|
if (!computeOp.getReductionOperands().empty())
|
|
updateRecipeUse<mlir::acc::ReductionOp>(
|
|
computeOp.getReductionOperands(), recipeName, op);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
std::unique_ptr<mlir::Pass> fir::acc::createACCRecipeBufferizationPass() {
|
|
return std::make_unique<ACCRecipeBufferization>();
|
|
}
|