1 | //===- llvm/unittests/IR/MemoryModelRelaxationAnnotationsTest.cpp ---------===// |
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/STLExtras.h" |
11 | #include "llvm/IR/Metadata.h" |
12 | #include "llvm/IR/Module.h" |
13 | #include "gtest/gtest.h" |
14 | |
15 | using namespace llvm; |
16 | |
17 | namespace { |
18 | |
19 | void checkMMRA(const MMRAMetadata &MMRA, |
20 | ArrayRef<MMRAMetadata::TagT> Expected) { |
21 | EXPECT_EQ(MMRA.size(), Expected.size()); |
22 | for (const auto &E : Expected) |
23 | EXPECT_TRUE(MMRA.hasTag(E.first, E.second)); |
24 | } |
25 | |
26 | MMRAMetadata createFromMD(LLVMContext &Ctx, |
27 | ArrayRef<MMRAMetadata::TagT> Expected) { |
28 | SmallVector<Metadata *> MD; |
29 | for (const auto &Tag : Expected) |
30 | MD.push_back(Elt: MMRAMetadata::getTagMD(Ctx, T: Tag)); |
31 | return MDTuple::get(Context&: Ctx, MDs: MD); |
32 | } |
33 | |
34 | TEST(MMRATest, MDParse) { |
35 | LLVMContext Ctx; |
36 | |
37 | // No nesting: |
38 | // !{!"foo", "!bar"} |
39 | MDNode *FooBar = |
40 | MDTuple::get(Context&: Ctx, MDs: {MDString::get(Context&: Ctx, Str: "foo" ), MDString::get(Context&: Ctx, Str: "bar" )}); |
41 | MMRAMetadata FooBarMMRA(FooBar); |
42 | |
43 | checkMMRA(MMRA: FooBarMMRA, Expected: {{"foo" , "bar" }}); |
44 | |
45 | // Nested: |
46 | // !{!{!"foo", "!bar"}, !{!"bux", !"qux"}} |
47 | MDNode *BuxQux = |
48 | MDTuple::get(Context&: Ctx, MDs: {MDString::get(Context&: Ctx, Str: "bux" ), MDString::get(Context&: Ctx, Str: "qux" )}); |
49 | MDNode *Nested = MDTuple::get(Context&: Ctx, MDs: {FooBar, BuxQux}); |
50 | MMRAMetadata NestedMMRA(Nested); |
51 | |
52 | checkMMRA(MMRA: NestedMMRA, Expected: {{"foo" , "bar" }, {"bux" , "qux" }}); |
53 | } |
54 | |
55 | TEST(MMRATest, GetMD) { |
56 | LLVMContext Ctx; |
57 | |
58 | EXPECT_EQ(MMRAMetadata::getMD(Ctx, {}), nullptr); |
59 | |
60 | MDTuple *SingleMD = MMRAMetadata::getMD(Ctx, Tags: {{"foo" , "bar" }}); |
61 | EXPECT_EQ(SingleMD->getNumOperands(), 2u); |
62 | EXPECT_EQ(cast<MDString>(SingleMD->getOperand(0))->getString(), "foo" ); |
63 | EXPECT_EQ(cast<MDString>(SingleMD->getOperand(1))->getString(), "bar" ); |
64 | |
65 | MDTuple *MultiMD = MMRAMetadata::getMD(Ctx, Tags: {{"foo" , "bar" }, {"bux" , "qux" }}); |
66 | EXPECT_EQ(MultiMD->getNumOperands(), 2u); |
67 | |
68 | MDTuple *FooBar = cast<MDTuple>(Val: MultiMD->getOperand(I: 0)); |
69 | EXPECT_EQ(cast<MDString>(FooBar->getOperand(0))->getString(), "foo" ); |
70 | EXPECT_EQ(cast<MDString>(FooBar->getOperand(1))->getString(), "bar" ); |
71 | MDTuple *BuxQux = cast<MDTuple>(Val: MultiMD->getOperand(I: 1)); |
72 | EXPECT_EQ(cast<MDString>(BuxQux->getOperand(0))->getString(), "bux" ); |
73 | EXPECT_EQ(cast<MDString>(BuxQux->getOperand(1))->getString(), "qux" ); |
74 | } |
75 | |
76 | TEST(MMRATest, Utility) { |
77 | LLVMContext Ctx; |
78 | MMRAMetadata MMRA = |
79 | createFromMD(Ctx, Expected: {{"foo" , "0" }, {"foo" , "1" }, {"bar" , "x" }}); |
80 | |
81 | EXPECT_TRUE(MMRA.hasTagWithPrefix("foo" )); |
82 | EXPECT_TRUE(MMRA.hasTagWithPrefix("bar" )); |
83 | EXPECT_FALSE(MMRA.hasTagWithPrefix("x" )); |
84 | |
85 | EXPECT_TRUE(MMRA.hasTag("foo" , "0" )); |
86 | EXPECT_TRUE(MMRA.hasTag("foo" , "1" )); |
87 | EXPECT_TRUE(MMRA.hasTag("bar" , "x" )); |
88 | } |
89 | |
90 | TEST(MMRATest, Operators) { |
91 | LLVMContext Ctx; |
92 | |
93 | MMRAMetadata A = createFromMD(Ctx, Expected: {{"foo" , "0" }, {"bar" , "x" }}); |
94 | MMRAMetadata B = createFromMD(Ctx, Expected: {{"foo" , "0" }, {"bar" , "y" }}); |
95 | |
96 | // ensure we have different objects by creating copies. |
97 | EXPECT_EQ(MMRAMetadata(A), MMRAMetadata(A)); |
98 | EXPECT_TRUE((bool)A); |
99 | |
100 | EXPECT_EQ(MMRAMetadata(B), MMRAMetadata(B)); |
101 | EXPECT_TRUE((bool)B); |
102 | |
103 | EXPECT_NE(A, B); |
104 | |
105 | EXPECT_EQ(MMRAMetadata(), MMRAMetadata()); |
106 | EXPECT_NE(A, MMRAMetadata()); |
107 | EXPECT_NE(B, MMRAMetadata()); |
108 | |
109 | MMRAMetadata Empty; |
110 | EXPECT_FALSE((bool)Empty); |
111 | } |
112 | |
113 | TEST(MMRATest, Compatibility) { |
114 | LLVMContext Ctx; |
115 | |
116 | MMRAMetadata Foo0 = createFromMD(Ctx, Expected: {{"foo" , "0" }}); |
117 | MMRAMetadata Foo1 = createFromMD(Ctx, Expected: {{"foo" , "1" }}); |
118 | MMRAMetadata Foo10 = createFromMD(Ctx, Expected: {{"foo" , "0" }, {"foo" , "1" }}); |
119 | |
120 | MMRAMetadata Bar = createFromMD(Ctx, Expected: {{"bar" , "y" }}); |
121 | |
122 | MMRAMetadata Empty; |
123 | |
124 | // Other set has no tag with same prefix |
125 | EXPECT_TRUE(Foo0.isCompatibleWith(Bar)); |
126 | EXPECT_TRUE(Bar.isCompatibleWith(Foo0)); |
127 | |
128 | EXPECT_TRUE(Foo0.isCompatibleWith(Empty)); |
129 | EXPECT_TRUE(Empty.isCompatibleWith(Foo0)); |
130 | |
131 | EXPECT_TRUE(Empty.isCompatibleWith(MMRAMetadata())); |
132 | EXPECT_TRUE(MMRAMetadata().isCompatibleWith(Empty)); |
133 | |
134 | // Other set has conflicting tags. |
135 | EXPECT_FALSE(Foo1.isCompatibleWith(Foo0)); |
136 | EXPECT_FALSE(Foo0.isCompatibleWith(Foo1)); |
137 | |
138 | // Both have common tags. |
139 | EXPECT_TRUE(Foo0.isCompatibleWith(Foo0)); |
140 | EXPECT_TRUE(Foo0.isCompatibleWith(Foo10)); |
141 | EXPECT_TRUE(Foo10.isCompatibleWith(Foo0)); |
142 | |
143 | EXPECT_TRUE(Foo1.isCompatibleWith(Foo1)); |
144 | EXPECT_TRUE(Foo1.isCompatibleWith(Foo10)); |
145 | EXPECT_TRUE(Foo10.isCompatibleWith(Foo1)); |
146 | |
147 | // Try with more prefixes now: |
148 | MMRAMetadata Multiple0 = |
149 | createFromMD(Ctx, Expected: {{"foo" , "y" }, {"foo" , "x" }, {"bar" , "z" }}); |
150 | MMRAMetadata Multiple1 = |
151 | createFromMD(Ctx, Expected: {{"foo" , "z" }, {"foo" , "x" }, {"bar" , "y" }}); |
152 | MMRAMetadata Multiple2 = |
153 | createFromMD(Ctx, Expected: {{"foo" , "z" }, {"foo" , "x" }, {"bux" , "y" }}); |
154 | |
155 | // Multiple0 and Multiple1 are not compatible because "bar" is getting in the |
156 | // way. |
157 | EXPECT_FALSE(Multiple0.isCompatibleWith(Multiple1)); |
158 | EXPECT_FALSE(Multiple1.isCompatibleWith(Multiple0)); |
159 | |
160 | EXPECT_TRUE(Multiple0.isCompatibleWith(Empty)); |
161 | EXPECT_TRUE(Empty.isCompatibleWith(Multiple0)); |
162 | EXPECT_TRUE(Multiple1.isCompatibleWith(Empty)); |
163 | EXPECT_TRUE(Empty.isCompatibleWith(Multiple1)); |
164 | |
165 | // Multiple2 is compatible with both 1/0 because there is always "foo:x" in |
166 | // common, and the other prefixes are unique to each set. |
167 | EXPECT_TRUE(Multiple2.isCompatibleWith(Multiple0)); |
168 | EXPECT_TRUE(Multiple0.isCompatibleWith(Multiple2)); |
169 | EXPECT_TRUE(Multiple2.isCompatibleWith(Multiple1)); |
170 | EXPECT_TRUE(Multiple1.isCompatibleWith(Multiple2)); |
171 | } |
172 | |
173 | TEST(MMRATest, Combine) { |
174 | LLVMContext Ctx; |
175 | |
176 | MMRAMetadata Foo0 = createFromMD(Ctx, Expected: {{"foo" , "0" }}); |
177 | MMRAMetadata Foo10 = createFromMD(Ctx, Expected: {{"foo" , "0" }, {"foo" , "1" }}); |
178 | MMRAMetadata Bar0 = createFromMD(Ctx, Expected: {{"bar" , "0" }}); |
179 | MMRAMetadata BarFoo0 = createFromMD(Ctx, Expected: {{"bar" , "0" }, {"foo" , "0" }}); |
180 | |
181 | { |
182 | // foo is common to both sets |
183 | MMRAMetadata Combined = MMRAMetadata::combine(Ctx, A: Foo0, B: Foo10); |
184 | EXPECT_EQ(Combined, Foo10); |
185 | } |
186 | |
187 | { |
188 | // nothing is common |
189 | MMRAMetadata Combined = MMRAMetadata::combine(Ctx, A: Foo0, B: Bar0); |
190 | EXPECT_TRUE(Combined.empty()); |
191 | } |
192 | |
193 | { |
194 | // only foo is common. |
195 | MMRAMetadata Combined = MMRAMetadata::combine(Ctx, A: BarFoo0, B: Foo0); |
196 | EXPECT_EQ(Combined, Foo0); |
197 | } |
198 | |
199 | { |
200 | // only bar is common. |
201 | MMRAMetadata Combined = MMRAMetadata::combine(Ctx, A: BarFoo0, B: Bar0); |
202 | EXPECT_EQ(Combined, Bar0); |
203 | } |
204 | |
205 | { |
206 | // only foo is common |
207 | MMRAMetadata Combined = MMRAMetadata::combine(Ctx, A: BarFoo0, B: Foo10); |
208 | EXPECT_EQ(Combined, Foo10); |
209 | } |
210 | } |
211 | |
212 | } // namespace |
213 | |