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