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/IR/Instructions.h"
11 #include "llvm/IR/Metadata.h"
12 #include "llvm/Support/Debug.h"
13 #include "llvm/Support/raw_ostream.h"
17 //===- MMRAMetadata -------------------------------------------------------===//
19 MMRAMetadata::MMRAMetadata(const Instruction
&I
)
20 : MMRAMetadata(I
.getMetadata(LLVMContext::MD_mmra
)) {}
22 MMRAMetadata::MMRAMetadata(MDNode
*MD
) {
26 // TODO: Split this into a "tryParse" function that can return an err.
27 // CTor can use the tryParse & just fatal on err.
29 MDTuple
*Tuple
= dyn_cast
<MDTuple
>(MD
);
30 assert(Tuple
&& "Invalid MMRA structure");
32 const auto HandleTagMD
= [this](MDNode
*TagMD
) {
33 Tags
.insert({cast
<MDString
>(TagMD
->getOperand(0))->getString(),
34 cast
<MDString
>(TagMD
->getOperand(1))->getString()});
42 for (const MDOperand
&Op
: Tuple
->operands()) {
43 MDNode
*MDOp
= cast
<MDNode
>(Op
.get());
44 assert(isTagMD(MDOp
));
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));
58 MDTuple
*MMRAMetadata::getTagMD(LLVMContext
&Ctx
, StringRef Prefix
,
60 return MDTuple::get(Ctx
,
61 {MDString::get(Ctx
, Prefix
), MDString::get(Ctx
, Suffix
)});
64 MDTuple
*MMRAMetadata::getMD(LLVMContext
&Ctx
,
65 ArrayRef
<MMRAMetadata::TagT
> Tags
) {
70 return getTagMD(Ctx
, Tags
.front());
72 SmallVector
<Metadata
*> MMRAs
;
73 for (const auto &Tag
: Tags
)
74 MMRAs
.push_back(getTagMD(Ctx
, Tag
));
75 return MDTuple::get(Ctx
, MMRAs
);
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
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.
87 SmallVector
<Metadata
*> Result
;
89 for (const auto &[P
, S
] : A
) {
90 if (B
.hasTagWithPrefix(P
))
91 Result
.push_back(getTagMD(Ctx
, P
, S
));
93 for (const auto &[P
, S
] : B
) {
94 if (A
.hasTagWithPrefix(P
))
95 Result
.push_back(getTagMD(Ctx
, P
, S
));
98 return MDTuple::get(Ctx
, Result
);
101 bool MMRAMetadata::hasTag(StringRef Prefix
, StringRef Suffix
) const {
102 return Tags
.count({Prefix
, Suffix
});
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.
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
));
117 for (auto &[Prefix
, Status
] : PrefixStatuses
) {
125 bool MMRAMetadata::hasTagWithPrefix(StringRef Prefix
) const {
126 for (const auto &[P
, S
] : Tags
)
132 MMRAMetadata::const_iterator
MMRAMetadata::begin() const {
136 MMRAMetadata::const_iterator
MMRAMetadata::end() const { return Tags
.end(); }
138 bool MMRAMetadata::empty() const { return Tags
.empty(); }
140 unsigned MMRAMetadata::size() const { return Tags
.size(); }
142 void MMRAMetadata::print(raw_ostream
&OS
) const {
144 // TODO: use map_iter + join
145 for (const auto &[P
, S
] : Tags
) {
155 void MMRAMetadata::dump() const { print(dbgs()); }
157 //===- Helpers ------------------------------------------------------------===//
159 static bool isReadWriteMemCall(const Instruction
&I
) {
160 if (const auto *C
= dyn_cast
<CallBase
>(&I
))
161 return C
->mayReadOrWriteMemory() ||
162 !C
->getMemoryEffects().doesNotAccessMemory();
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
);