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