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