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