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