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