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