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