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