1 //===- MemoryModelRelaxationAnnotations.cpp ---------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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"
18 //===- MMRAMetadata -------------------------------------------------------===//
20 MMRAMetadata::MMRAMetadata(const Instruction
&I
)
21 : MMRAMetadata(I
.getMetadata(LLVMContext::MD_mmra
)) {}
23 MMRAMetadata::MMRAMetadata(MDNode
*MD
) {
27 // TODO: Split this into a "tryParse" function that can return an err.
28 // CTor can use the tryParse & just fatal on err.
30 MDTuple
*Tuple
= dyn_cast
<MDTuple
>(MD
);
31 assert(Tuple
&& "Invalid MMRA structure");
33 const auto HandleTagMD
= [this](MDNode
*TagMD
) {
34 Tags
.insert({cast
<MDString
>(TagMD
->getOperand(0))->getString(),
35 cast
<MDString
>(TagMD
->getOperand(1))->getString()});
43 for (const MDOperand
&Op
: Tuple
->operands()) {
44 MDNode
*MDOp
= cast
<MDNode
>(Op
.get());
45 assert(isTagMD(MDOp
));
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));
59 MDTuple
*MMRAMetadata::getTagMD(LLVMContext
&Ctx
, StringRef Prefix
,
61 return MDTuple::get(Ctx
,
62 {MDString::get(Ctx
, Prefix
), MDString::get(Ctx
, Suffix
)});
65 MDTuple
*MMRAMetadata::getMD(LLVMContext
&Ctx
,
66 ArrayRef
<MMRAMetadata::TagT
> Tags
) {
71 return getTagMD(Ctx
, Tags
.front());
73 SmallVector
<Metadata
*> MMRAs
;
74 for (const auto &Tag
: Tags
)
75 MMRAs
.push_back(getTagMD(Ctx
, Tag
));
76 return MDTuple::get(Ctx
, MMRAs
);
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
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.
88 SmallVector
<Metadata
*> Result
;
90 for (const auto &[P
, S
] : A
) {
91 if (B
.hasTagWithPrefix(P
))
92 Result
.push_back(getTagMD(Ctx
, P
, S
));
94 for (const auto &[P
, S
] : B
) {
95 if (A
.hasTagWithPrefix(P
))
96 Result
.push_back(getTagMD(Ctx
, P
, S
));
99 return MDTuple::get(Ctx
, Result
);
102 bool MMRAMetadata::hasTag(StringRef Prefix
, StringRef Suffix
) const {
103 return Tags
.count({Prefix
, Suffix
});
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.
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
));
118 for (auto &[Prefix
, Status
] : PrefixStatuses
) {
126 bool MMRAMetadata::hasTagWithPrefix(StringRef Prefix
) const {
127 for (const auto &[P
, S
] : Tags
)
133 MMRAMetadata::const_iterator
MMRAMetadata::begin() const {
137 MMRAMetadata::const_iterator
MMRAMetadata::end() const { return Tags
.end(); }
139 bool MMRAMetadata::empty() const { return Tags
.empty(); }
141 unsigned MMRAMetadata::size() const { return Tags
.size(); }
143 void MMRAMetadata::print(raw_ostream
&OS
) const {
145 // TODO: use map_iter + join
146 for (const auto &[P
, S
] : Tags
) {
156 void MMRAMetadata::dump() const { print(dbgs()); }
158 //===- Helpers ------------------------------------------------------------===//
160 static bool isReadWriteMemCall(const Instruction
&I
) {
161 if (const auto *C
= dyn_cast
<CallBase
>(&I
))
162 return C
->mayReadOrWriteMemory() ||
163 !C
->getMemoryEffects().doesNotAccessMemory();
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
);