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