1 | //===-- TBAABuilder.cpp -- TBAA builder definitions -----------------------===// |
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 | // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "flang/Optimizer/CodeGen/TBAABuilder.h" |
14 | #include "flang/Optimizer/Dialect/FIRType.h" |
15 | #include "llvm/ADT/TypeSwitch.h" |
16 | #include "llvm/Support/CommandLine.h" |
17 | #include "llvm/Support/Debug.h" |
18 | #include <mlir/Dialect/LLVMIR/LLVMAttrs.h> |
19 | #include <mlir/Dialect/LLVMIR/LLVMDialect.h> |
20 | #include <mlir/Dialect/LLVMIR/LLVMTypes.h> |
21 | |
22 | #define DEBUG_TYPE "flang-tbaa-builder" |
23 | |
24 | using namespace mlir; |
25 | using namespace mlir::LLVM; |
26 | |
27 | static llvm::cl::opt<bool> disableTBAA( |
28 | "disable-tbaa" , |
29 | llvm::cl::desc("disable attaching TBAA tags to memory accessing operations " |
30 | "to override default Flang behavior" ), |
31 | llvm::cl::init(Val: false)); |
32 | |
33 | // disabling this will play badly with the FIR TBAA pass, leading to worse |
34 | // performance |
35 | static llvm::cl::opt<bool> perFunctionTBAATrees( |
36 | "per-function-tbaa-trees" , |
37 | llvm::cl::desc("Give each function an independent TBAA tree (default)" ), |
38 | llvm::cl::init(Val: true), llvm::cl::Hidden); |
39 | |
40 | // tagAttachmentLimit is a debugging option that allows limiting |
41 | // the number of TBAA access tag attributes attached to operations. |
42 | // It is set to kTagAttachmentUnlimited by default denoting "no limit". |
43 | static constexpr unsigned kTagAttachmentUnlimited = |
44 | std::numeric_limits<unsigned>::max(); |
45 | static llvm::cl::opt<unsigned> |
46 | tagAttachmentLimit("tbaa-attach-tag-max" , llvm::cl::desc("" ), |
47 | llvm::cl::init(Val: kTagAttachmentUnlimited)); |
48 | |
49 | namespace fir { |
50 | |
51 | TBAABuilder::TBAABuilder(MLIRContext *context, bool applyTBAA, |
52 | bool forceUnifiedTree) |
53 | : enableTBAA(applyTBAA && !disableTBAA), |
54 | trees(/*separatePerFunction=*/perFunctionTBAATrees && !forceUnifiedTree) { |
55 | // TODO: the TBAA tags created here are rooted in the root scope |
56 | // of the enclosing function. This does not work best with MLIR inlining. |
57 | // A better approach is to root them according to the scopes they belong to |
58 | // and that were used by AddAliasTagsPass to create TBAA tags before |
59 | // the CodeGen. For example: |
60 | // subroutine caller(a, b, ptr) |
61 | // real, target :: a(:), b(:) |
62 | // integer, pointer :: ptr(:) |
63 | // call callee(a, b, ptr) |
64 | // end |
65 | // subroutine callee(a, b, ptr) |
66 | // real :: a(:), b(:) |
67 | // integer, pointer :: ptr(:) |
68 | // do i=... |
69 | // a(ptr(i)) = b(ptr(i)) |
70 | // end do |
71 | // end |
72 | // |
73 | // When callee is inlined, the dummy arguments 'a' and 'b' will |
74 | // be rooted in TBAA tree corresponding to the `call callee` call site, |
75 | // saying that the references to 'a' and 'b' cannot alias each other. |
76 | // These tags will be created by AddAliasTagsPass, but it will not be able |
77 | // to create any tags for 'ptr' references. |
78 | // During the CodeGen, we create 'any data access' tags for the |
79 | // 'ptr' acceses. If they are rooted within the root scope of `caller`, |
80 | // they end up in a different TBAA tree with the 'a' and 'b' access |
81 | // tags, so 'ptr', 'a' and 'b' references MayAlias. Moreover, |
82 | // the box access of 'ptr' will also be in a different TBAA tree |
83 | // with 'a' and 'b' tags, meaning they can also alias. |
84 | // This will prevent LLVM vectorization even with memory conflict checks. |
85 | // It seems that we'd better move all TBAA tags assignment to |
86 | // AddAliasTagsPass, which can at least rely on the dummy arguments scopes. |
87 | if (!enableTBAA) |
88 | return; |
89 | } |
90 | |
91 | TBAATagAttr TBAABuilder::getAccessTag(TBAATypeDescriptorAttr baseTypeDesc, |
92 | TBAATypeDescriptorAttr accessTypeDesc, |
93 | int64_t offset) { |
94 | TBAATagAttr &tag = tagsMap[{baseTypeDesc, accessTypeDesc, offset}]; |
95 | if (tag) |
96 | return tag; |
97 | |
98 | // Initialize new tag. |
99 | tag = TBAATagAttr::get(baseTypeDesc, accessTypeDesc, offset); |
100 | return tag; |
101 | } |
102 | |
103 | TBAATagAttr TBAABuilder::getAnyBoxAccessTag(mlir::LLVM::LLVMFuncOp func) { |
104 | TBAATypeDescriptorAttr boxMemberTypeDesc = trees[func].boxMemberTypeDesc; |
105 | return getAccessTag(boxMemberTypeDesc, boxMemberTypeDesc, /*offset=*/0); |
106 | } |
107 | |
108 | TBAATagAttr TBAABuilder::getBoxAccessTag(Type baseFIRType, Type accessFIRType, |
109 | GEPOp gep, |
110 | mlir::LLVM::LLVMFuncOp func) { |
111 | return getAnyBoxAccessTag(func); |
112 | } |
113 | |
114 | TBAATagAttr TBAABuilder::getAnyDataAccessTag(mlir::LLVM::LLVMFuncOp func) { |
115 | TBAATypeDescriptorAttr anyDataAccessTypeDesc = trees[func].anyDataTypeDesc; |
116 | return getAccessTag(anyDataAccessTypeDesc, anyDataAccessTypeDesc, |
117 | /*offset=*/0); |
118 | } |
119 | |
120 | TBAATagAttr TBAABuilder::getDataAccessTag(Type baseFIRType, Type accessFIRType, |
121 | GEPOp gep, |
122 | mlir::LLVM::LLVMFuncOp func) { |
123 | return getAnyDataAccessTag(func); |
124 | } |
125 | |
126 | TBAATagAttr TBAABuilder::getAnyAccessTag(mlir::LLVM::LLVMFuncOp func) { |
127 | TBAATypeDescriptorAttr anyAccessTypeDesc = trees[func].anyAccessDesc; |
128 | return getAccessTag(anyAccessTypeDesc, anyAccessTypeDesc, /*offset=*/0); |
129 | } |
130 | |
131 | void TBAABuilder::attachTBAATag(AliasAnalysisOpInterface op, Type baseFIRType, |
132 | Type accessFIRType, GEPOp gep) { |
133 | if (!enableTBAA) |
134 | return; |
135 | |
136 | mlir::LLVM::LLVMFuncOp func = op->getParentOfType<mlir::LLVM::LLVMFuncOp>(); |
137 | if (!func) |
138 | return; |
139 | |
140 | ++tagAttachmentCounter; |
141 | if (tagAttachmentLimit != kTagAttachmentUnlimited && |
142 | tagAttachmentCounter > tagAttachmentLimit) |
143 | return; |
144 | |
145 | LLVM_DEBUG(llvm::dbgs() << "Attaching TBAA tag #" << tagAttachmentCounter |
146 | << "\n" ); |
147 | |
148 | TBAATagAttr tbaaTagSym; |
149 | if (fir::isRecordWithDescriptorMember(baseFIRType)) { |
150 | // A memory access that addresses an aggregate that contains |
151 | // a mix of data members and descriptor members may alias |
152 | // with both data and descriptor accesses. |
153 | // Conservatively set any-access tag if there is any descriptor member. |
154 | tbaaTagSym = getAnyAccessTag(func); |
155 | } else if (mlir::isa<fir::BaseBoxType>(baseFIRType)) { |
156 | tbaaTagSym = getBoxAccessTag(baseFIRType, accessFIRType, gep, func); |
157 | } else { |
158 | tbaaTagSym = getDataAccessTag(baseFIRType, accessFIRType, gep, func); |
159 | } |
160 | |
161 | if (!tbaaTagSym) |
162 | return; |
163 | |
164 | op.setTBAATags(ArrayAttr::get(op->getContext(), tbaaTagSym)); |
165 | } |
166 | |
167 | } // namespace fir |
168 | |