blob: f5e2c35733f21079c8aec30484dcc69be5ec53a5 [file] [edit]
//===-- EmitMIFGlobalCtors.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
//
//===----------------------------------------------------------------------===//
#include "flang/Optimizer/Builder/MIFCommon.h"
#include "flang/Optimizer/Builder/Runtime/Inquiry.h"
#include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/MIF/MIFOps.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/Pass/Pass.h"
namespace fir {
#define GEN_PASS_DEF_EMITMIFGLOBALCTORS
#include "flang/Optimizer/Transforms/Passes.h.inc"
} // namespace fir
using namespace mlir;
using namespace Fortran::runtime;
namespace {
class EmitMIFGlobalCtors
: public fir::impl::EmitMIFGlobalCtorsBase<EmitMIFGlobalCtors> {
public:
void runOnOperation() override {
mlir::ModuleOp mod = getOperation();
mlir::MLIRContext *ctx = mod.getContext();
mlir::OpBuilder builder(ctx);
builder.setInsertionPointToEnd(mod.getBody());
mlir::Location loc = builder.getUnknownLoc();
llvm::SmallVector<mlir::Attribute> funcs, priorities, data;
mlir::Type i32Ty = mlir::IntegerType::get(ctx, 32);
mlir::Attribute zeroAttr = mlir::LLVM::ZeroAttr::get(builder.getContext());
// Setting priority 0 for the initialization of mif.
if (mod.lookupSymbol<mlir::LLVM::LLVMFuncOp>(mifSaveCoarraysAllocName)) {
funcs.push_back(
mlir::FlatSymbolRefAttr::get(ctx, mifSaveCoarraysAllocName));
priorities.push_back(mlir::IntegerAttr::get(i32Ty, 0));
data.push_back(zeroAttr);
}
if (funcs.empty())
return;
// We check whether a GlobalCtorsOp already exists to avoid having
// multiple instances.
mlir::LLVM::GlobalCtorsOp globalCtors;
mod.walk([&](mlir::LLVM::GlobalCtorsOp op) { globalCtors = op; });
if (globalCtors) {
llvm::SmallVector<mlir::Attribute> mergedFuncs(
globalCtors.getCtors().begin(), globalCtors.getCtors().end());
llvm::SmallVector<mlir::Attribute> mergedPriorities(
globalCtors.getPriorities().begin(),
globalCtors.getPriorities().end());
llvm::SmallVector<mlir::Attribute> mergedData(
globalCtors.getData().begin(), globalCtors.getData().end());
llvm::SmallDenseSet<llvm::StringRef> existingNames;
for (auto attr : globalCtors.getCtors())
existingNames.insert(
llvm::cast<mlir::FlatSymbolRefAttr>(attr).getValue());
for (auto [func, priority, d] : llvm::zip(funcs, priorities, data)) {
auto name = llvm::cast<mlir::FlatSymbolRefAttr>(func).getValue();
if (!existingNames.contains(name)) {
mergedFuncs.push_back(func);
mergedPriorities.push_back(priority);
mergedData.push_back(d);
}
}
// Deleting the existing GlobalCtorsOp and creating a new one that
// contains the merged attributes.
builder.setInsertionPoint(globalCtors);
mlir::LLVM::GlobalCtorsOp::create(builder, globalCtors.getLoc(),
builder.getArrayAttr(mergedFuncs),
builder.getArrayAttr(mergedPriorities),
builder.getArrayAttr(mergedData));
globalCtors.erase();
} else {
builder.setInsertionPointToEnd(mod.getBody());
mlir::LLVM::GlobalCtorsOp::create(
builder, loc, builder.getArrayAttr(funcs),
builder.getArrayAttr(priorities), builder.getArrayAttr(data));
}
}
};
} // namespace