aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/IR/MemoryModelRelaxationAnnotations.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2024-07-27 23:34:35 +0000
committerDimitry Andric <dim@FreeBSD.org>2024-10-23 18:26:01 +0000
commit0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583 (patch)
tree6cf5ab1f05330c6773b1f3f64799d56a9c7a1faa /contrib/llvm-project/llvm/lib/IR/MemoryModelRelaxationAnnotations.cpp
parent6b9f7133aba44189d9625c352bc2c2a59baf18ef (diff)
parentac9a064cb179f3425b310fa2847f8764ac970a4d (diff)
Diffstat (limited to 'contrib/llvm-project/llvm/lib/IR/MemoryModelRelaxationAnnotations.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/IR/MemoryModelRelaxationAnnotations.cpp170
1 files changed, 170 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/IR/MemoryModelRelaxationAnnotations.cpp b/contrib/llvm-project/llvm/lib/IR/MemoryModelRelaxationAnnotations.cpp
new file mode 100644
index 000000000000..19f438d890ae
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/IR/MemoryModelRelaxationAnnotations.cpp
@@ -0,0 +1,170 @@
+//===- 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/ADT/StringSet.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);
+}