1 //===- MemoryModelRelaxationAnnotations.cpp ---------------------*- C++ -*-===// 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 #include "llvm/IR/MemoryModelRelaxationAnnotations.h" 10 #include "llvm/ADT/StringSet.h" 11 #include "llvm/IR/Instructions.h" 12 #include "llvm/IR/Metadata.h" 13 #include "llvm/Support/Debug.h" 14 #include "llvm/Support/raw_ostream.h" 15 16 using namespace llvm; 17 18 //===- MMRAMetadata -------------------------------------------------------===// 19 20 MMRAMetadata::MMRAMetadata(const Instruction &I) 21 : MMRAMetadata(I.getMetadata(LLVMContext::MD_mmra)) {} 22 23 MMRAMetadata::MMRAMetadata(MDNode *MD) { 24 if (!MD) 25 return; 26 27 // TODO: Split this into a "tryParse" function that can return an err. 28 // CTor can use the tryParse & just fatal on err. 29 30 MDTuple *Tuple = dyn_cast<MDTuple>(MD); 31 assert(Tuple && "Invalid MMRA structure"); 32 33 const auto HandleTagMD = [this](MDNode *TagMD) { 34 Tags.insert({cast<MDString>(TagMD->getOperand(0))->getString(), 35 cast<MDString>(TagMD->getOperand(1))->getString()}); 36 }; 37 38 if (isTagMD(Tuple)) { 39 HandleTagMD(Tuple); 40 return; 41 } 42 43 for (const MDOperand &Op : Tuple->operands()) { 44 MDNode *MDOp = cast<MDNode>(Op.get()); 45 assert(isTagMD(MDOp)); 46 HandleTagMD(MDOp); 47 } 48 } 49 50 bool MMRAMetadata::isTagMD(const Metadata *MD) { 51 if (auto *Tuple = dyn_cast<MDTuple>(MD)) { 52 return Tuple->getNumOperands() == 2 && 53 isa<MDString>(Tuple->getOperand(0)) && 54 isa<MDString>(Tuple->getOperand(1)); 55 } 56 return false; 57 } 58 59 MDTuple *MMRAMetadata::getTagMD(LLVMContext &Ctx, StringRef Prefix, 60 StringRef Suffix) { 61 return MDTuple::get(Ctx, 62 {MDString::get(Ctx, Prefix), MDString::get(Ctx, Suffix)}); 63 } 64 65 MDTuple *MMRAMetadata::getMD(LLVMContext &Ctx, 66 ArrayRef<MMRAMetadata::TagT> Tags) { 67 if (Tags.empty()) 68 return nullptr; 69 70 if (Tags.size() == 1) 71 return getTagMD(Ctx, Tags.front()); 72 73 SmallVector<Metadata *> MMRAs; 74 for (const auto &Tag : Tags) 75 MMRAs.push_back(getTagMD(Ctx, Tag)); 76 return MDTuple::get(Ctx, MMRAs); 77 } 78 79 MDNode *MMRAMetadata::combine(LLVMContext &Ctx, const MMRAMetadata &A, 80 const MMRAMetadata &B) { 81 // Let A and B be two tags set, and U be the prefix-wise union of A and B. 82 // For every unique tag prefix P present in A or B: 83 // * If either A or B has no tags with prefix P, no tags with prefix 84 // P are added to U. 85 // * If both A and B have at least one tag with prefix P, all tags with prefix 86 // P from both sets are added to U. 87 88 SmallVector<Metadata *> Result; 89 90 for (const auto &[P, S] : A) { 91 if (B.hasTagWithPrefix(P)) 92 Result.push_back(getTagMD(Ctx, P, S)); 93 } 94 for (const auto &[P, S] : B) { 95 if (A.hasTagWithPrefix(P)) 96 Result.push_back(getTagMD(Ctx, P, S)); 97 } 98 99 return MDTuple::get(Ctx, Result); 100 } 101 102 bool MMRAMetadata::hasTag(StringRef Prefix, StringRef Suffix) const { 103 return Tags.count({Prefix, Suffix}); 104 } 105 106 bool MMRAMetadata::isCompatibleWith(const MMRAMetadata &Other) const { 107 // Two sets of tags are compatible iff, for every unique tag prefix P 108 // present in at least one set: 109 // - the other set contains no tag with prefix P, or 110 // - at least one tag with prefix P is common to both sets. 111 112 StringMap<bool> PrefixStatuses; 113 for (const auto &[P, S] : Tags) 114 PrefixStatuses[P] |= (Other.hasTag(P, S) || !Other.hasTagWithPrefix(P)); 115 for (const auto &[P, S] : Other) 116 PrefixStatuses[P] |= (hasTag(P, S) || !hasTagWithPrefix(P)); 117 118 for (auto &[Prefix, Status] : PrefixStatuses) { 119 if (!Status) 120 return false; 121 } 122 123 return true; 124 } 125 126 bool MMRAMetadata::hasTagWithPrefix(StringRef Prefix) const { 127 for (const auto &[P, S] : Tags) 128 if (P == Prefix) 129 return true; 130 return false; 131 } 132 133 MMRAMetadata::const_iterator MMRAMetadata::begin() const { 134 return Tags.begin(); 135 } 136 137 MMRAMetadata::const_iterator MMRAMetadata::end() const { return Tags.end(); } 138 139 bool MMRAMetadata::empty() const { return Tags.empty(); } 140 141 unsigned MMRAMetadata::size() const { return Tags.size(); } 142 143 void MMRAMetadata::print(raw_ostream &OS) const { 144 bool IsFirst = true; 145 // TODO: use map_iter + join 146 for (const auto &[P, S] : Tags) { 147 if (IsFirst) 148 IsFirst = false; 149 else 150 OS << ", "; 151 OS << P << ":" << S; 152 } 153 } 154 155 LLVM_DUMP_METHOD 156 void MMRAMetadata::dump() const { print(dbgs()); } 157 158 //===- Helpers ------------------------------------------------------------===// 159 160 static bool isReadWriteMemCall(const Instruction &I) { 161 if (const auto *C = dyn_cast<CallBase>(&I)) 162 return C->mayReadOrWriteMemory() || 163 !C->getMemoryEffects().doesNotAccessMemory(); 164 return false; 165 } 166 167 bool llvm::canInstructionHaveMMRAs(const Instruction &I) { 168 return isa<LoadInst>(I) || isa<StoreInst>(I) || isa<AtomicCmpXchgInst>(I) || 169 isa<AtomicRMWInst>(I) || isa<FenceInst>(I) || isReadWriteMemCall(I); 170 } 171