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