//===- llvm/unittests/IR/MemoryModelRelaxationAnnotationsTest.cpp ---------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/IR/MemoryModelRelaxationAnnotations.h" #include "llvm/ADT/STLExtras.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "gtest/gtest.h" using namespace llvm; namespace { void checkMMRA(const MMRAMetadata &MMRA, ArrayRef Expected) { EXPECT_EQ(MMRA.size(), Expected.size()); for (const auto &E : Expected) EXPECT_TRUE(MMRA.hasTag(E.first, E.second)); } MMRAMetadata createFromMD(LLVMContext &Ctx, ArrayRef Expected) { SmallVector MD; for (const auto &Tag : Expected) MD.push_back(MMRAMetadata::getTagMD(Ctx, Tag)); return MDTuple::get(Ctx, MD); } TEST(MMRATest, MDParse) { LLVMContext Ctx; // No nesting: // !{!"foo", "!bar"} MDNode *FooBar = MDTuple::get(Ctx, {MDString::get(Ctx, "foo"), MDString::get(Ctx, "bar")}); MMRAMetadata FooBarMMRA(FooBar); checkMMRA(FooBarMMRA, {{"foo", "bar"}}); // Nested: // !{!{!"foo", "!bar"}, !{!"bux", !"qux"}} MDNode *BuxQux = MDTuple::get(Ctx, {MDString::get(Ctx, "bux"), MDString::get(Ctx, "qux")}); MDNode *Nested = MDTuple::get(Ctx, {FooBar, BuxQux}); MMRAMetadata NestedMMRA(Nested); checkMMRA(NestedMMRA, {{"foo", "bar"}, {"bux", "qux"}}); } TEST(MMRATest, GetMD) { LLVMContext Ctx; EXPECT_EQ(MMRAMetadata::getMD(Ctx, {}), nullptr); MDTuple *SingleMD = MMRAMetadata::getMD(Ctx, {{"foo", "bar"}}); EXPECT_EQ(SingleMD->getNumOperands(), 2u); EXPECT_EQ(cast(SingleMD->getOperand(0))->getString(), "foo"); EXPECT_EQ(cast(SingleMD->getOperand(1))->getString(), "bar"); MDTuple *MultiMD = MMRAMetadata::getMD(Ctx, {{"foo", "bar"}, {"bux", "qux"}}); EXPECT_EQ(MultiMD->getNumOperands(), 2u); MDTuple *FooBar = cast(MultiMD->getOperand(0)); EXPECT_EQ(cast(FooBar->getOperand(0))->getString(), "foo"); EXPECT_EQ(cast(FooBar->getOperand(1))->getString(), "bar"); MDTuple *BuxQux = cast(MultiMD->getOperand(1)); EXPECT_EQ(cast(BuxQux->getOperand(0))->getString(), "bux"); EXPECT_EQ(cast(BuxQux->getOperand(1))->getString(), "qux"); } TEST(MMRATest, Utility) { LLVMContext Ctx; MMRAMetadata MMRA = createFromMD(Ctx, {{"foo", "0"}, {"foo", "1"}, {"bar", "x"}}); EXPECT_TRUE(MMRA.hasTagWithPrefix("foo")); EXPECT_TRUE(MMRA.hasTagWithPrefix("bar")); EXPECT_FALSE(MMRA.hasTagWithPrefix("x")); EXPECT_TRUE(MMRA.hasTag("foo", "0")); EXPECT_TRUE(MMRA.hasTag("foo", "1")); EXPECT_TRUE(MMRA.hasTag("bar", "x")); } TEST(MMRATest, Operators) { LLVMContext Ctx; MMRAMetadata A = createFromMD(Ctx, {{"foo", "0"}, {"bar", "x"}}); MMRAMetadata B = createFromMD(Ctx, {{"foo", "0"}, {"bar", "y"}}); // ensure we have different objects by creating copies. EXPECT_EQ(MMRAMetadata(A), MMRAMetadata(A)); EXPECT_TRUE((bool)A); EXPECT_EQ(MMRAMetadata(B), MMRAMetadata(B)); EXPECT_TRUE((bool)B); EXPECT_NE(A, B); EXPECT_EQ(MMRAMetadata(), MMRAMetadata()); EXPECT_NE(A, MMRAMetadata()); EXPECT_NE(B, MMRAMetadata()); MMRAMetadata Empty; EXPECT_FALSE((bool)Empty); } TEST(MMRATest, Compatibility) { LLVMContext Ctx; MMRAMetadata Foo0 = createFromMD(Ctx, {{"foo", "0"}}); MMRAMetadata Foo1 = createFromMD(Ctx, {{"foo", "1"}}); MMRAMetadata Foo10 = createFromMD(Ctx, {{"foo", "0"}, {"foo", "1"}}); MMRAMetadata Bar = createFromMD(Ctx, {{"bar", "y"}}); MMRAMetadata Empty; // Other set has no tag with same prefix EXPECT_TRUE(Foo0.isCompatibleWith(Bar)); EXPECT_TRUE(Bar.isCompatibleWith(Foo0)); EXPECT_TRUE(Foo0.isCompatibleWith(Empty)); EXPECT_TRUE(Empty.isCompatibleWith(Foo0)); EXPECT_TRUE(Empty.isCompatibleWith(MMRAMetadata())); EXPECT_TRUE(MMRAMetadata().isCompatibleWith(Empty)); // Other set has conflicting tags. EXPECT_FALSE(Foo1.isCompatibleWith(Foo0)); EXPECT_FALSE(Foo0.isCompatibleWith(Foo1)); // Both have common tags. EXPECT_TRUE(Foo0.isCompatibleWith(Foo0)); EXPECT_TRUE(Foo0.isCompatibleWith(Foo10)); EXPECT_TRUE(Foo10.isCompatibleWith(Foo0)); EXPECT_TRUE(Foo1.isCompatibleWith(Foo1)); EXPECT_TRUE(Foo1.isCompatibleWith(Foo10)); EXPECT_TRUE(Foo10.isCompatibleWith(Foo1)); // Try with more prefixes now: MMRAMetadata Multiple0 = createFromMD(Ctx, {{"foo", "y"}, {"foo", "x"}, {"bar", "z"}}); MMRAMetadata Multiple1 = createFromMD(Ctx, {{"foo", "z"}, {"foo", "x"}, {"bar", "y"}}); MMRAMetadata Multiple2 = createFromMD(Ctx, {{"foo", "z"}, {"foo", "x"}, {"bux", "y"}}); // Multiple0 and Multiple1 are not compatible because "bar" is getting in the // way. EXPECT_FALSE(Multiple0.isCompatibleWith(Multiple1)); EXPECT_FALSE(Multiple1.isCompatibleWith(Multiple0)); EXPECT_TRUE(Multiple0.isCompatibleWith(Empty)); EXPECT_TRUE(Empty.isCompatibleWith(Multiple0)); EXPECT_TRUE(Multiple1.isCompatibleWith(Empty)); EXPECT_TRUE(Empty.isCompatibleWith(Multiple1)); // Multiple2 is compatible with both 1/0 because there is always "foo:x" in // common, and the other prefixes are unique to each set. EXPECT_TRUE(Multiple2.isCompatibleWith(Multiple0)); EXPECT_TRUE(Multiple0.isCompatibleWith(Multiple2)); EXPECT_TRUE(Multiple2.isCompatibleWith(Multiple1)); EXPECT_TRUE(Multiple1.isCompatibleWith(Multiple2)); } TEST(MMRATest, Combine) { LLVMContext Ctx; MMRAMetadata Foo0 = createFromMD(Ctx, {{"foo", "0"}}); MMRAMetadata Foo10 = createFromMD(Ctx, {{"foo", "0"}, {"foo", "1"}}); MMRAMetadata Bar0 = createFromMD(Ctx, {{"bar", "0"}}); MMRAMetadata BarFoo0 = createFromMD(Ctx, {{"bar", "0"}, {"foo", "0"}}); { // foo is common to both sets MMRAMetadata Combined = MMRAMetadata::combine(Ctx, Foo0, Foo10); EXPECT_EQ(Combined, Foo10); } { // nothing is common MMRAMetadata Combined = MMRAMetadata::combine(Ctx, Foo0, Bar0); EXPECT_TRUE(Combined.empty()); } { // only foo is common. MMRAMetadata Combined = MMRAMetadata::combine(Ctx, BarFoo0, Foo0); EXPECT_EQ(Combined, Foo0); } { // only bar is common. MMRAMetadata Combined = MMRAMetadata::combine(Ctx, BarFoo0, Bar0); EXPECT_EQ(Combined, Bar0); } { // only foo is common MMRAMetadata Combined = MMRAMetadata::combine(Ctx, BarFoo0, Foo10); EXPECT_EQ(Combined, Foo10); } } } // namespace