xref: /llvm-project/flang/lib/Optimizer/CodeGen/TBAABuilder.cpp (revision 6cd86d0fae8cbb752a713860f131b9b759b2cbb8)
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(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(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(kTagAttachmentUnlimited));
48 
49 namespace fir {
50 
TBAABuilder(MLIRContext * context,bool applyTBAA,bool forceUnifiedTree)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 
getAccessTag(TBAATypeDescriptorAttr baseTypeDesc,TBAATypeDescriptorAttr accessTypeDesc,int64_t offset)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 
getAnyBoxAccessTag(mlir::LLVM::LLVMFuncOp func)103 TBAATagAttr TBAABuilder::getAnyBoxAccessTag(mlir::LLVM::LLVMFuncOp func) {
104   TBAATypeDescriptorAttr boxMemberTypeDesc = trees[func].boxMemberTypeDesc;
105   return getAccessTag(boxMemberTypeDesc, boxMemberTypeDesc, /*offset=*/0);
106 }
107 
getBoxAccessTag(Type baseFIRType,Type accessFIRType,GEPOp gep,mlir::LLVM::LLVMFuncOp func)108 TBAATagAttr TBAABuilder::getBoxAccessTag(Type baseFIRType, Type accessFIRType,
109                                          GEPOp gep,
110                                          mlir::LLVM::LLVMFuncOp func) {
111   return getAnyBoxAccessTag(func);
112 }
113 
getAnyDataAccessTag(mlir::LLVM::LLVMFuncOp func)114 TBAATagAttr TBAABuilder::getAnyDataAccessTag(mlir::LLVM::LLVMFuncOp func) {
115   TBAATypeDescriptorAttr anyDataAccessTypeDesc = trees[func].anyDataTypeDesc;
116   return getAccessTag(anyDataAccessTypeDesc, anyDataAccessTypeDesc,
117                       /*offset=*/0);
118 }
119 
getDataAccessTag(Type baseFIRType,Type accessFIRType,GEPOp gep,mlir::LLVM::LLVMFuncOp func)120 TBAATagAttr TBAABuilder::getDataAccessTag(Type baseFIRType, Type accessFIRType,
121                                           GEPOp gep,
122                                           mlir::LLVM::LLVMFuncOp func) {
123   return getAnyDataAccessTag(func);
124 }
125 
getAnyAccessTag(mlir::LLVM::LLVMFuncOp func)126 TBAATagAttr TBAABuilder::getAnyAccessTag(mlir::LLVM::LLVMFuncOp func) {
127   TBAATypeDescriptorAttr anyAccessTypeDesc = trees[func].anyAccessDesc;
128   return getAccessTag(anyAccessTypeDesc, anyAccessTypeDesc, /*offset=*/0);
129 }
130 
attachTBAATag(AliasAnalysisOpInterface op,Type baseFIRType,Type accessFIRType,GEPOp gep)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