//===-- TBAAForest.h - A TBAA tree for each function -----------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef FORTRAN_OPTIMIZER_ANALYSIS_TBAA_FOREST_H
#define FORTRAN_OPTIMIZER_ANALYSIS_TBAA_FOREST_H
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/MLIRContext.h"
#include "llvm/ADT/DenseMap.h"
#include <string>
namespace fir {
//===----------------------------------------------------------------------===//
// TBAATree
//===----------------------------------------------------------------------===//
/// Per-function TBAA tree. Each tree contains branches for data (of various
/// kinds) and descriptor access
struct TBAATree {
//===----------------------------------------------------------------------===//
// TBAAForrest::TBAATree::SubtreeState
//===----------------------------------------------------------------------===//
/// This contains a TBAA subtree based on some parent. New tags can be added
/// under the parent using getTag.
class SubtreeState {
friend TBAATree; // only allow construction by TBAATree
public:
SubtreeState() = delete;
SubtreeState(const SubtreeState &) = delete;
SubtreeState(SubtreeState &&) = default;
mlir::LLVM::TBAATagAttr getTag(llvm::StringRef uniqueId) const;
private:
SubtreeState(mlir::MLIRContext *ctx, std::string name,
mlir::LLVM::TBAANodeAttr grandParent)
: parentId{std::move(name)}, context(ctx) {
parent = mlir::LLVM::TBAATypeDescriptorAttr::get(
context, parentId, mlir::LLVM::TBAAMemberAttr::get(grandParent, 0));
}
const std::string parentId;
mlir::MLIRContext *const context;
mlir::LLVM::TBAATypeDescriptorAttr parent;
llvm::DenseMap<llvm::StringRef, mlir::LLVM::TBAATagAttr> tagDedup;
};
SubtreeState globalDataTree;
SubtreeState allocatedDataTree;
SubtreeState dummyArgDataTree;
SubtreeState directDataTree;
mlir::LLVM::TBAATypeDescriptorAttr anyAccessDesc;
mlir::LLVM::TBAATypeDescriptorAttr boxMemberTypeDesc;
mlir::LLVM::TBAATypeDescriptorAttr anyDataTypeDesc;
static TBAATree buildTree(mlir::StringAttr functionName);
private:
TBAATree(mlir::LLVM::TBAATypeDescriptorAttr anyAccess,
mlir::LLVM::TBAATypeDescriptorAttr dataRoot,
mlir::LLVM::TBAATypeDescriptorAttr boxMemberTypeDesc);
};
//===----------------------------------------------------------------------===//
// TBAAForrest
//===----------------------------------------------------------------------===//
/// Collection of TBAATrees, usually indexed by function (so that each function
/// has a different TBAATree)
class TBAAForrest {
public:
explicit TBAAForrest(bool separatePerFunction = true)
: separatePerFunction{separatePerFunction} {}
inline const TBAATree &operator[](mlir::func::FuncOp func) {
return getFuncTree(func.getSymNameAttr());
}
inline const TBAATree &operator[](mlir::LLVM::LLVMFuncOp func) {
// the external name conversion pass may rename some functions. Their old
// name must be used so that we add to the tbaa tree added in the FIR pass
mlir::Attribute attr = func->getAttr(getInternalFuncNameAttrName());
if (attr) {
return getFuncTree(mlir::cast<mlir::StringAttr>(attr));
}
return getFuncTree(func.getSymNameAttr());
}
// Returns the TBAA tree associated with the scope enclosed
// within the given function. With MLIR inlining, there may
// be multiple scopes within a single function. It is the caller's
// responsibility to provide unique name for the scope.
// If the scope string is empty, returns the TBAA tree for the
// "root" scope of the given function.
inline const TBAATree &getFuncTreeWithScope(mlir::func::FuncOp func,
llvm::StringRef scope) {
mlir::StringAttr name = func.getSymNameAttr();
if (!scope.empty())
name = mlir::StringAttr::get(name.getContext(),
llvm::Twine(name) + " - " + scope);
return getFuncTree(name);
}
private:
const TBAATree &getFuncTree(mlir::StringAttr symName) {
if (!separatePerFunction)
symName = mlir::StringAttr::get(symName.getContext(), "");
if (!trees.contains(symName))
trees.insert({symName, TBAATree::buildTree(symName)});
return trees.at(symName);
}
// Should each function use a different tree?
const bool separatePerFunction;
// TBAA tree per function
llvm::DenseMap<mlir::StringAttr, TBAATree> trees;
};
} // namespace fir
#endif // FORTRAN_OPTIMIZER_ANALYSIS_TBAA_FOREST_H