xref: /llvm-project/flang/lib/Optimizer/CodeGen/TBAABuilder.cpp (revision b14763652f8519e9ec6b10667a17e32bc3dce913)
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 "TBAABuilder.h"
14 #include "flang/Optimizer/Dialect/FIRType.h"
15 #include "llvm/Support/CommandLine.h"
16 #include "llvm/Support/Debug.h"
17 
18 #define DEBUG_TYPE "flang-tbaa-builder"
19 
20 using namespace mlir;
21 using namespace mlir::LLVM;
22 
23 static llvm::cl::opt<bool> disableTBAA(
24     "disable-tbaa",
25     llvm::cl::desc("disable attaching TBAA tags to memory accessing operations "
26                    "to override default Flang behavior"),
27     llvm::cl::init(false));
28 
29 // tagAttachmentLimit is a debugging option that allows limiting
30 // the number of TBAA access tag attributes attached to operations.
31 // It is set to kTagAttachmentUnlimited by default denoting "no limit".
32 static constexpr unsigned kTagAttachmentUnlimited =
33     std::numeric_limits<unsigned>::max();
34 static llvm::cl::opt<unsigned>
35     tagAttachmentLimit("tbaa-attach-tag-max", llvm::cl::desc(""),
36                        llvm::cl::init(kTagAttachmentUnlimited));
37 
38 namespace fir {
39 std::string TBAABuilder::getNewTBAANodeName(llvm::StringRef basename) {
40   return (llvm::Twine(basename) + llvm::Twine('_') +
41           llvm::Twine(tbaaNodeCounter++))
42       .str();
43 }
44 
45 TBAABuilder::TBAABuilder(mlir::ModuleOp module, bool applyTBAA)
46     : enableTBAA(applyTBAA && !disableTBAA) {
47   if (!enableTBAA)
48     return;
49 
50   // In the usual Flang compilation flow, FIRToLLVMPass is run once,
51   // and the MetadataOp holding TBAA operations is created at the beginning
52   // of the pass. With tools like tco it is possible to invoke
53   // FIRToLLVMPass on already converted MLIR, so the MetadataOp
54   // already exists and creating a new one with the same name would
55   // be incorrect. If the TBAA MetadataOp is already present,
56   // we just disable all TBAABuilder actions (e.g. attachTBAATag()
57   // is a no-op).
58   if (llvm::any_of(
59           module.getBodyRegion().getOps<LLVM::MetadataOp>(),
60           [&](auto metaOp) { return metaOp.getSymName() == tbaaMetaOpName; })) {
61     enableTBAA = false;
62     return;
63   }
64 
65   LLVM_DEBUG(llvm::dbgs() << "Creating TBAA MetadataOp for module '"
66                           << module.getName().value_or("<unknown>") << "'\n");
67 
68   // Create TBAA MetadataOp with the root and basic type descriptors.
69   Location loc = module.getLoc();
70   MLIRContext *context = module.getContext();
71   OpBuilder builder(module.getBody(), module.getBody()->end());
72   tbaaMetaOp = builder.create<MetadataOp>(loc, tbaaMetaOpName);
73   builder.setInsertionPointToStart(&tbaaMetaOp.getBody().front());
74 
75   // Root node.
76   auto rootOp = builder.create<TBAARootMetadataOp>(
77       loc, getNewTBAANodeName(kRootSymBasename), flangTBAARootId);
78   flangTBAARoot = FlatSymbolRefAttr::get(rootOp);
79 
80   // Any access node.
81   auto anyAccessOp = builder.create<TBAATypeDescriptorOp>(
82       loc, getNewTBAANodeName(kTypeDescSymBasename),
83       StringAttr::get(context, anyAccessTypeDescId),
84       ArrayAttr::get(context, flangTBAARoot), ArrayRef<int64_t>{0});
85   anyAccessTypeDesc = FlatSymbolRefAttr::get(anyAccessOp);
86 
87   // Any data access node.
88   auto anyDataAccessOp = builder.create<TBAATypeDescriptorOp>(
89       loc, getNewTBAANodeName(kTypeDescSymBasename),
90       StringAttr::get(context, anyDataAccessTypeDescId),
91       ArrayAttr::get(context, anyAccessTypeDesc), ArrayRef<int64_t>{0});
92   anyDataAccessTypeDesc = FlatSymbolRefAttr::get(anyDataAccessOp);
93 
94   // Box member access node.
95   auto boxMemberOp = builder.create<TBAATypeDescriptorOp>(
96       loc, getNewTBAANodeName(kTypeDescSymBasename),
97       StringAttr::get(context, boxMemberTypeDescId),
98       ArrayAttr::get(context, anyAccessTypeDesc), ArrayRef<int64_t>{0});
99   boxMemberTypeDesc = FlatSymbolRefAttr::get(boxMemberOp);
100 }
101 
102 SymbolRefAttr TBAABuilder::getAccessTag(SymbolRefAttr baseTypeDesc,
103                                         SymbolRefAttr accessTypeDesc,
104                                         int64_t offset) {
105   SymbolRefAttr &tag = tagsMap[{baseTypeDesc, accessTypeDesc, offset}];
106   if (tag)
107     return tag;
108 
109   // Initialize new tag.
110   Location loc = tbaaMetaOp.getLoc();
111   OpBuilder builder(&tbaaMetaOp.getBody().back(),
112                     tbaaMetaOp.getBody().back().end());
113   auto tagOp = builder.create<TBAATagOp>(
114       loc, getNewTBAANodeName(kTagSymBasename), baseTypeDesc.getLeafReference(),
115       accessTypeDesc.getLeafReference(), offset);
116   // TBAATagOp symbols must be referenced by their fully qualified
117   // names, so create a path to TBAATagOp symbol.
118   StringAttr metaOpName = SymbolTable::getSymbolName(tbaaMetaOp);
119   tag = SymbolRefAttr::get(builder.getContext(), metaOpName,
120                            FlatSymbolRefAttr::get(tagOp));
121   return tag;
122 }
123 
124 SymbolRefAttr TBAABuilder::getAnyBoxAccessTag() {
125   return getAccessTag(boxMemberTypeDesc, boxMemberTypeDesc, /*offset=*/0);
126 }
127 
128 SymbolRefAttr TBAABuilder::getBoxAccessTag(Type baseFIRType, Type accessFIRType,
129                                            GEPOp gep) {
130   return getAnyBoxAccessTag();
131 }
132 
133 SymbolRefAttr TBAABuilder::getAnyDataAccessTag() {
134   return getAccessTag(anyDataAccessTypeDesc, anyDataAccessTypeDesc,
135                       /*offset=*/0);
136 }
137 
138 SymbolRefAttr TBAABuilder::getDataAccessTag(Type baseFIRType,
139                                             Type accessFIRType, GEPOp gep) {
140   return getAnyDataAccessTag();
141 }
142 
143 void TBAABuilder::attachTBAATag(Operation *op, Type baseFIRType,
144                                 Type accessFIRType, GEPOp gep) {
145   if (!enableTBAA)
146     return;
147 
148   ++tagAttachmentCounter;
149   if (tagAttachmentLimit != kTagAttachmentUnlimited &&
150       tagAttachmentCounter > tagAttachmentLimit)
151     return;
152 
153   LLVM_DEBUG(llvm::dbgs() << "Attaching TBAA tag #" << tagAttachmentCounter
154                           << "\n");
155 
156   SymbolRefAttr tbaaTagSym;
157   if (baseFIRType.isa<fir::BaseBoxType>())
158     tbaaTagSym = getBoxAccessTag(baseFIRType, accessFIRType, gep);
159   else
160     tbaaTagSym = getDataAccessTag(baseFIRType, accessFIRType, gep);
161 
162   if (tbaaTagSym)
163     op->setAttr(LLVMDialect::getTBAAAttrName(),
164                 ArrayAttr::get(op->getContext(), tbaaTagSym));
165 }
166 
167 } // namespace fir
168