mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 14:16:08 +00:00
170 lines
5.0 KiB
C++
170 lines
5.0 KiB
C++
//===- MemoryModelRelaxationAnnotations.cpp ---------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/IR/MemoryModelRelaxationAnnotations.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/IR/Metadata.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace llvm;
|
|
|
|
//===- MMRAMetadata -------------------------------------------------------===//
|
|
|
|
MMRAMetadata::MMRAMetadata(const Instruction &I)
|
|
: MMRAMetadata(I.getMetadata(LLVMContext::MD_mmra)) {}
|
|
|
|
MMRAMetadata::MMRAMetadata(MDNode *MD) {
|
|
if (!MD)
|
|
return;
|
|
|
|
// TODO: Split this into a "tryParse" function that can return an err.
|
|
// CTor can use the tryParse & just fatal on err.
|
|
|
|
MDTuple *Tuple = dyn_cast<MDTuple>(MD);
|
|
assert(Tuple && "Invalid MMRA structure");
|
|
|
|
const auto HandleTagMD = [this](MDNode *TagMD) {
|
|
Tags.insert({cast<MDString>(TagMD->getOperand(0))->getString(),
|
|
cast<MDString>(TagMD->getOperand(1))->getString()});
|
|
};
|
|
|
|
if (isTagMD(Tuple)) {
|
|
HandleTagMD(Tuple);
|
|
return;
|
|
}
|
|
|
|
for (const MDOperand &Op : Tuple->operands()) {
|
|
MDNode *MDOp = cast<MDNode>(Op.get());
|
|
assert(isTagMD(MDOp));
|
|
HandleTagMD(MDOp);
|
|
}
|
|
}
|
|
|
|
bool MMRAMetadata::isTagMD(const Metadata *MD) {
|
|
if (auto *Tuple = dyn_cast<MDTuple>(MD)) {
|
|
return Tuple->getNumOperands() == 2 &&
|
|
isa<MDString>(Tuple->getOperand(0)) &&
|
|
isa<MDString>(Tuple->getOperand(1));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
MDTuple *MMRAMetadata::getTagMD(LLVMContext &Ctx, StringRef Prefix,
|
|
StringRef Suffix) {
|
|
return MDTuple::get(Ctx,
|
|
{MDString::get(Ctx, Prefix), MDString::get(Ctx, Suffix)});
|
|
}
|
|
|
|
MDTuple *MMRAMetadata::getMD(LLVMContext &Ctx,
|
|
ArrayRef<MMRAMetadata::TagT> Tags) {
|
|
if (Tags.empty())
|
|
return nullptr;
|
|
|
|
if (Tags.size() == 1)
|
|
return getTagMD(Ctx, Tags.front());
|
|
|
|
SmallVector<Metadata *> MMRAs;
|
|
for (const auto &Tag : Tags)
|
|
MMRAs.push_back(getTagMD(Ctx, Tag));
|
|
return MDTuple::get(Ctx, MMRAs);
|
|
}
|
|
|
|
MDNode *MMRAMetadata::combine(LLVMContext &Ctx, const MMRAMetadata &A,
|
|
const MMRAMetadata &B) {
|
|
// Let A and B be two tags set, and U be the prefix-wise union of A and B.
|
|
// For every unique tag prefix P present in A or B:
|
|
// * If either A or B has no tags with prefix P, no tags with prefix
|
|
// P are added to U.
|
|
// * If both A and B have at least one tag with prefix P, all tags with prefix
|
|
// P from both sets are added to U.
|
|
|
|
SmallVector<Metadata *> Result;
|
|
|
|
for (const auto &[P, S] : A) {
|
|
if (B.hasTagWithPrefix(P))
|
|
Result.push_back(getTagMD(Ctx, P, S));
|
|
}
|
|
for (const auto &[P, S] : B) {
|
|
if (A.hasTagWithPrefix(P))
|
|
Result.push_back(getTagMD(Ctx, P, S));
|
|
}
|
|
|
|
return MDTuple::get(Ctx, Result);
|
|
}
|
|
|
|
bool MMRAMetadata::hasTag(StringRef Prefix, StringRef Suffix) const {
|
|
return Tags.count({Prefix, Suffix});
|
|
}
|
|
|
|
bool MMRAMetadata::isCompatibleWith(const MMRAMetadata &Other) const {
|
|
// Two sets of tags are compatible iff, for every unique tag prefix P
|
|
// present in at least one set:
|
|
// - the other set contains no tag with prefix P, or
|
|
// - at least one tag with prefix P is common to both sets.
|
|
|
|
StringMap<bool> PrefixStatuses;
|
|
for (const auto &[P, S] : Tags)
|
|
PrefixStatuses[P] |= (Other.hasTag(P, S) || !Other.hasTagWithPrefix(P));
|
|
for (const auto &[P, S] : Other)
|
|
PrefixStatuses[P] |= (hasTag(P, S) || !hasTagWithPrefix(P));
|
|
|
|
for (auto &[Prefix, Status] : PrefixStatuses) {
|
|
if (!Status)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool MMRAMetadata::hasTagWithPrefix(StringRef Prefix) const {
|
|
for (const auto &[P, S] : Tags)
|
|
if (P == Prefix)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
MMRAMetadata::const_iterator MMRAMetadata::begin() const {
|
|
return Tags.begin();
|
|
}
|
|
|
|
MMRAMetadata::const_iterator MMRAMetadata::end() const { return Tags.end(); }
|
|
|
|
bool MMRAMetadata::empty() const { return Tags.empty(); }
|
|
|
|
unsigned MMRAMetadata::size() const { return Tags.size(); }
|
|
|
|
void MMRAMetadata::print(raw_ostream &OS) const {
|
|
bool IsFirst = true;
|
|
// TODO: use map_iter + join
|
|
for (const auto &[P, S] : Tags) {
|
|
if (IsFirst)
|
|
IsFirst = false;
|
|
else
|
|
OS << ", ";
|
|
OS << P << ":" << S;
|
|
}
|
|
}
|
|
|
|
LLVM_DUMP_METHOD
|
|
void MMRAMetadata::dump() const { print(dbgs()); }
|
|
|
|
//===- Helpers ------------------------------------------------------------===//
|
|
|
|
static bool isReadWriteMemCall(const Instruction &I) {
|
|
if (const auto *C = dyn_cast<CallBase>(&I))
|
|
return C->mayReadOrWriteMemory() ||
|
|
!C->getMemoryEffects().doesNotAccessMemory();
|
|
return false;
|
|
}
|
|
|
|
bool llvm::canInstructionHaveMMRAs(const Instruction &I) {
|
|
return isa<LoadInst>(I) || isa<StoreInst>(I) || isa<AtomicCmpXchgInst>(I) ||
|
|
isa<AtomicRMWInst>(I) || isa<FenceInst>(I) || isReadWriteMemCall(I);
|
|
}
|