Path: blob/main/contrib/llvm-project/llvm/lib/IR/MemoryModelRelaxationAnnotations.cpp
35233 views
//===- MemoryModelRelaxationAnnotations.cpp ---------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/IR/MemoryModelRelaxationAnnotations.h"9#include "llvm/ADT/StringSet.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"1415using namespace llvm;1617//===- MMRAMetadata -------------------------------------------------------===//1819MMRAMetadata::MMRAMetadata(const Instruction &I)20: MMRAMetadata(I.getMetadata(LLVMContext::MD_mmra)) {}2122MMRAMetadata::MMRAMetadata(MDNode *MD) {23if (!MD)24return;2526// TODO: Split this into a "tryParse" function that can return an err.27// CTor can use the tryParse & just fatal on err.2829MDTuple *Tuple = dyn_cast<MDTuple>(MD);30assert(Tuple && "Invalid MMRA structure");3132const auto HandleTagMD = [this](MDNode *TagMD) {33Tags.insert({cast<MDString>(TagMD->getOperand(0))->getString(),34cast<MDString>(TagMD->getOperand(1))->getString()});35};3637if (isTagMD(Tuple)) {38HandleTagMD(Tuple);39return;40}4142for (const MDOperand &Op : Tuple->operands()) {43MDNode *MDOp = cast<MDNode>(Op.get());44assert(isTagMD(MDOp));45HandleTagMD(MDOp);46}47}4849bool MMRAMetadata::isTagMD(const Metadata *MD) {50if (auto *Tuple = dyn_cast<MDTuple>(MD)) {51return Tuple->getNumOperands() == 2 &&52isa<MDString>(Tuple->getOperand(0)) &&53isa<MDString>(Tuple->getOperand(1));54}55return false;56}5758MDTuple *MMRAMetadata::getTagMD(LLVMContext &Ctx, StringRef Prefix,59StringRef Suffix) {60return MDTuple::get(Ctx,61{MDString::get(Ctx, Prefix), MDString::get(Ctx, Suffix)});62}6364MDTuple *MMRAMetadata::getMD(LLVMContext &Ctx,65ArrayRef<MMRAMetadata::TagT> Tags) {66if (Tags.empty())67return nullptr;6869if (Tags.size() == 1)70return getTagMD(Ctx, Tags.front());7172SmallVector<Metadata *> MMRAs;73for (const auto &Tag : Tags)74MMRAs.push_back(getTagMD(Ctx, Tag));75return MDTuple::get(Ctx, MMRAs);76}7778MDNode *MMRAMetadata::combine(LLVMContext &Ctx, const MMRAMetadata &A,79const 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 prefix83// P are added to U.84// * If both A and B have at least one tag with prefix P, all tags with prefix85// P from both sets are added to U.8687SmallVector<Metadata *> Result;8889for (const auto &[P, S] : A) {90if (B.hasTagWithPrefix(P))91Result.push_back(getTagMD(Ctx, P, S));92}93for (const auto &[P, S] : B) {94if (A.hasTagWithPrefix(P))95Result.push_back(getTagMD(Ctx, P, S));96}9798return MDTuple::get(Ctx, Result);99}100101bool MMRAMetadata::hasTag(StringRef Prefix, StringRef Suffix) const {102return Tags.count({Prefix, Suffix});103}104105bool MMRAMetadata::isCompatibleWith(const MMRAMetadata &Other) const {106// Two sets of tags are compatible iff, for every unique tag prefix P107// present in at least one set:108// - the other set contains no tag with prefix P, or109// - at least one tag with prefix P is common to both sets.110111StringMap<bool> PrefixStatuses;112for (const auto &[P, S] : Tags)113PrefixStatuses[P] |= (Other.hasTag(P, S) || !Other.hasTagWithPrefix(P));114for (const auto &[P, S] : Other)115PrefixStatuses[P] |= (hasTag(P, S) || !hasTagWithPrefix(P));116117for (auto &[Prefix, Status] : PrefixStatuses) {118if (!Status)119return false;120}121122return true;123}124125bool MMRAMetadata::hasTagWithPrefix(StringRef Prefix) const {126for (const auto &[P, S] : Tags)127if (P == Prefix)128return true;129return false;130}131132MMRAMetadata::const_iterator MMRAMetadata::begin() const {133return Tags.begin();134}135136MMRAMetadata::const_iterator MMRAMetadata::end() const { return Tags.end(); }137138bool MMRAMetadata::empty() const { return Tags.empty(); }139140unsigned MMRAMetadata::size() const { return Tags.size(); }141142void MMRAMetadata::print(raw_ostream &OS) const {143bool IsFirst = true;144// TODO: use map_iter + join145for (const auto &[P, S] : Tags) {146if (IsFirst)147IsFirst = false;148else149OS << ", ";150OS << P << ":" << S;151}152}153154LLVM_DUMP_METHOD155void MMRAMetadata::dump() const { print(dbgs()); }156157//===- Helpers ------------------------------------------------------------===//158159static bool isReadWriteMemCall(const Instruction &I) {160if (const auto *C = dyn_cast<CallBase>(&I))161return C->mayReadOrWriteMemory() ||162!C->getMemoryEffects().doesNotAccessMemory();163return false;164}165166bool llvm::canInstructionHaveMMRAs(const Instruction &I) {167return isa<LoadInst>(I) || isa<StoreInst>(I) || isa<AtomicCmpXchgInst>(I) ||168isa<AtomicRMWInst>(I) || isa<FenceInst>(I) || isReadWriteMemCall(I);169}170171172