Skip to content

Commit df5c278

Browse files
committed
[flang][FIR] add FIR TBAA pass
See RFC at https://discourse.llvm.org/t/rfc-propagate-fir-alias-analysis-information-using-tbaa/73755 This pass adds TBAA tags to all accesses to non-pointer/target dummy arguments. These TBAA tags tell LLVM that these accesses cannot alias: allowing better dead code elimination, hoisting out of loops, and vectorization. Each function has its own TBAA tree so that accesses between funtions MayAlias after inlining. I also included code for adding tags for local allocations and for global variables. Enabling all three kinds of tag is known to produce a miscompile and so these are disabled by default. But it isn't much code and I thought it could be interesting to play with these later if one is looking at a benchmark which looks like it would benefit from more alias information. I'm open to removing this code too. TBAA tags are also added separately by TBAABuilder during CodeGen. TBAABuilder has to run during CodeGen because it adds tags to box accesses, many of which are implicit in FIR. This pass cannot (easily) run in CodeGen because fir::AliasAnalysis has difficulty tracing values between blocks, and by the time CodeGen runs, structured control flow has already been lowered. Coming in follow up patches - Change CodeGen/TBAABuilder to use TBAAForest to add tags within the same per-function trees as are used here (delayed to a later patch to make it easier to revert) - Command line argument processing to actually enable the pass
1 parent 02678bc commit df5c278

File tree

9 files changed

+958
-0
lines changed

9 files changed

+958
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//===-- TBAAForest.h - A TBAA tree for each function -----------*- C++ -*-===//
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+
#ifndef FORTRAN_OPTIMIZER_ANALYSIS_TBAA_FOREST_H
10+
#define FORTRAN_OPTIMIZER_ANALYSIS_TBAA_FOREST_H
11+
12+
#include "mlir/Dialect/Func/IR/FuncOps.h"
13+
#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
14+
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
15+
#include "mlir/IR/MLIRContext.h"
16+
#include "llvm/ADT/DenseMap.h"
17+
#include <string>
18+
19+
namespace fir {
20+
21+
//===----------------------------------------------------------------------===//
22+
// TBAATree
23+
//===----------------------------------------------------------------------===//
24+
/// Per-function TBAA tree. Each tree contains branches for data (of various
25+
/// kinds) and descriptor access
26+
struct TBAATree {
27+
//===----------------------------------------------------------------------===//
28+
// TBAAForrest::TBAATree::SubtreeState
29+
//===----------------------------------------------------------------------===//
30+
/// This contains a TBAA subtree based on some parent. New tags can be added
31+
/// under the parent using getTag.
32+
class SubtreeState {
33+
friend TBAATree; // only allow construction by TBAATree
34+
public:
35+
SubtreeState() = delete;
36+
SubtreeState(const SubtreeState &) = delete;
37+
SubtreeState(SubtreeState &&) = default;
38+
39+
mlir::LLVM::TBAATagAttr getTag(llvm::StringRef uniqueId) const;
40+
41+
private:
42+
SubtreeState(mlir::MLIRContext *ctx, std::string name,
43+
mlir::LLVM::TBAANodeAttr grandParent)
44+
: parentId{std::move(name)}, context(ctx) {
45+
parent = mlir::LLVM::TBAATypeDescriptorAttr::get(
46+
context, parentId, mlir::LLVM::TBAAMemberAttr::get(grandParent, 0));
47+
}
48+
49+
const std::string parentId;
50+
mlir::MLIRContext *const context;
51+
mlir::LLVM::TBAATypeDescriptorAttr parent;
52+
llvm::DenseMap<llvm::StringRef, mlir::LLVM::TBAATagAttr> tagDedup;
53+
};
54+
55+
SubtreeState globalDataTree;
56+
SubtreeState allocatedDataTree;
57+
SubtreeState dummyArgDataTree;
58+
mlir::LLVM::TBAATypeDescriptorAttr anyAccessDesc;
59+
mlir::LLVM::TBAATypeDescriptorAttr boxMemberTypeDesc;
60+
mlir::LLVM::TBAATypeDescriptorAttr anyDataTypeDesc;
61+
62+
static TBAATree buildTree(mlir::StringAttr functionName);
63+
64+
private:
65+
TBAATree(mlir::LLVM::TBAATypeDescriptorAttr anyAccess,
66+
mlir::LLVM::TBAATypeDescriptorAttr dataRoot,
67+
mlir::LLVM::TBAATypeDescriptorAttr boxMemberTypeDesc);
68+
};
69+
70+
//===----------------------------------------------------------------------===//
71+
// TBAAForrest
72+
//===----------------------------------------------------------------------===//
73+
/// Collection of TBAATrees, usually indexed by function (so that each function
74+
/// has a different TBAATree)
75+
class TBAAForrest {
76+
public:
77+
explicit TBAAForrest(bool separatePerFunction = true)
78+
: separatePerFunction{separatePerFunction} {}
79+
80+
inline const TBAATree &operator[](mlir::func::FuncOp func) {
81+
return getFuncTree(func.getSymNameAttr());
82+
}
83+
inline const TBAATree &operator[](mlir::LLVM::LLVMFuncOp func) {
84+
return getFuncTree(func.getSymNameAttr());
85+
}
86+
87+
private:
88+
const TBAATree &getFuncTree(mlir::StringAttr symName) {
89+
if (!separatePerFunction)
90+
symName = mlir::StringAttr::get(symName.getContext(), "");
91+
if (!trees.contains(symName))
92+
trees.insert({symName, TBAATree::buildTree(symName)});
93+
return trees.at(symName);
94+
}
95+
96+
// Should each function use a different tree?
97+
const bool separatePerFunction;
98+
// TBAA tree per function
99+
llvm::DenseMap<mlir::StringAttr, TBAATree> trees;
100+
};
101+
102+
} // namespace fir
103+
104+
#endif // FORTRAN_OPTIMIZER_ANALYSIS_TBAA_FOREST_H

flang/include/flang/Optimizer/Transforms/Passes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ std::unique_ptr<mlir::Pass> createMemDataFlowOptPass();
6161
std::unique_ptr<mlir::Pass> createPromoteToAffinePass();
6262
std::unique_ptr<mlir::Pass> createMemoryAllocationPass();
6363
std::unique_ptr<mlir::Pass> createStackArraysPass();
64+
std::unique_ptr<mlir::Pass> createAliasTagsPass();
6465
std::unique_ptr<mlir::Pass> createSimplifyIntrinsicsPass();
6566
std::unique_ptr<mlir::Pass> createAddDebugFoundationPass();
6667
std::unique_ptr<mlir::Pass> createLoopVersioningPass();

flang/include/flang/Optimizer/Transforms/Passes.td

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,26 @@ def StackArrays : Pass<"stack-arrays", "mlir::ModuleOp"> {
252252
let constructor = "::fir::createStackArraysPass()";
253253
}
254254

255+
def AddAliasTags : Pass<"fir-add-alias-tags", "mlir::ModuleOp"> {
256+
let summary = "Add tbaa tags to operations that implement FirAliasAnalysisOpInterface";
257+
let description = [{
258+
TBAA (type based alias analysis) is one method to pass pointer alias information
259+
from language frontends to LLVM. This pass uses fir::AliasAnalysis to add this
260+
information to fir.load and fir.store operations.
261+
Additional tags are added during codegen. See fir::TBAABuilder.
262+
This needs to be a separate pass so that it happens before structured control
263+
flow operations are lowered to branches and basic blocks (this makes tracing
264+
the source of values much eaiser). The other TBAA tags need to be applied to
265+
box loads and stores which are implicit in FIR and so cannot be annotated
266+
until codegen.
267+
TODO: this is currently a pass on mlir::ModuleOp to avoid parallelism. In
268+
theory, each operation could be considered in prallel, so long as there
269+
aren't races adding new tags to the mlir context.
270+
}];
271+
let dependentDialects = [ "fir::FIROpsDialect" ];
272+
let constructor = "::fir::createAliasTagsPass()";
273+
}
274+
255275
def SimplifyRegionLite : Pass<"simplify-region-lite", "mlir::ModuleOp"> {
256276
let summary = "Region simplification";
257277
let description = [{

flang/lib/Optimizer/Analysis/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
add_flang_library(FIRAnalysis
22
AliasAnalysis.cpp
3+
TBAAForest.cpp
34

45
DEPENDS
56
FIRDialect
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//===- TBAAForest.cpp - Per-functon TBAA Trees ----------------------------===//
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 "flang/Optimizer/Analysis/TBAAForest.h"
10+
#include <mlir/Dialect/LLVMIR/LLVMAttrs.h>
11+
12+
mlir::LLVM::TBAATagAttr
13+
fir::TBAATree::SubtreeState::getTag(llvm::StringRef uniqueName) const {
14+
// mlir::LLVM::TBAATagAttr &tag = tagDedup[uniqueName];
15+
// if (tag)
16+
// return tag;
17+
std::string id = (parentId + "/" + uniqueName).str();
18+
mlir::LLVM::TBAATypeDescriptorAttr type =
19+
mlir::LLVM::TBAATypeDescriptorAttr::get(
20+
context, id, mlir::LLVM::TBAAMemberAttr::get(parent, 0));
21+
return mlir::LLVM::TBAATagAttr::get(type, type, 0);
22+
// return tag;
23+
}
24+
25+
fir::TBAATree fir::TBAATree::buildTree(mlir::StringAttr func) {
26+
llvm::StringRef funcName = func.getValue();
27+
std::string rootId = ("Flang function root " + funcName).str();
28+
mlir::MLIRContext *ctx = func.getContext();
29+
mlir::LLVM::TBAARootAttr funcRoot =
30+
mlir::LLVM::TBAARootAttr::get(ctx, mlir::StringAttr::get(ctx, rootId));
31+
32+
static constexpr llvm::StringRef anyAccessTypeDescId = "any access";
33+
mlir::LLVM::TBAATypeDescriptorAttr anyAccess =
34+
mlir::LLVM::TBAATypeDescriptorAttr::get(
35+
ctx, anyAccessTypeDescId,
36+
mlir::LLVM::TBAAMemberAttr::get(funcRoot, 0));
37+
38+
static constexpr llvm::StringRef anyDataAccessTypeDescId = "any data access";
39+
mlir::LLVM::TBAATypeDescriptorAttr dataRoot =
40+
mlir::LLVM::TBAATypeDescriptorAttr::get(
41+
ctx, anyDataAccessTypeDescId,
42+
mlir::LLVM::TBAAMemberAttr::get(anyAccess, 0));
43+
44+
static constexpr llvm::StringRef boxMemberTypeDescId = "descriptor member";
45+
mlir::LLVM::TBAATypeDescriptorAttr boxMemberTypeDesc =
46+
mlir::LLVM::TBAATypeDescriptorAttr::get(
47+
ctx, boxMemberTypeDescId,
48+
mlir::LLVM::TBAAMemberAttr::get(anyAccess, 0));
49+
50+
return TBAATree{anyAccess, dataRoot, boxMemberTypeDesc};
51+
}
52+
53+
fir::TBAATree::TBAATree(mlir::LLVM::TBAATypeDescriptorAttr anyAccess,
54+
mlir::LLVM::TBAATypeDescriptorAttr dataRoot,
55+
mlir::LLVM::TBAATypeDescriptorAttr boxMemberTypeDesc)
56+
: globalDataTree(dataRoot.getContext(), "global data", dataRoot),
57+
allocatedDataTree(dataRoot.getContext(), "allocated data", dataRoot),
58+
dummyArgDataTree(dataRoot.getContext(), "dummy arg data", dataRoot),
59+
anyAccessDesc(anyAccess), boxMemberTypeDesc(boxMemberTypeDesc),
60+
anyDataTypeDesc(dataRoot) {}

0 commit comments

Comments
 (0)