summaryrefslogtreecommitdiff
path: root/llvm/unittests/IR/DataLayoutTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/unittests/IR/DataLayoutTest.cpp')
-rw-r--r--llvm/unittests/IR/DataLayoutTest.cpp140
1 files changed, 135 insertions, 5 deletions
diff --git a/llvm/unittests/IR/DataLayoutTest.cpp b/llvm/unittests/IR/DataLayoutTest.cpp
index e0c0f35847f0..9ca88141ca0e 100644
--- a/llvm/unittests/IR/DataLayoutTest.cpp
+++ b/llvm/unittests/IR/DataLayoutTest.cpp
@@ -320,7 +320,8 @@ TEST(DataLayout, ParsePointerSpec) {
"\"p[<n>]:<size>:<abi>[:<pref>[:<idx>]]\""));
// address space
- for (StringRef Str : {"p0x0:32:32", "px:32:32:32", "p16777216:32:32:32:32"})
+ for (StringRef Str :
+ {"p0x0:32:32", "p10_000:32:32:32", "p16777216:32:32:32:32"})
EXPECT_THAT_EXPECTED(
DataLayout::parse(Str),
FailedWithMessage("address space must be a 24-bit integer"));
@@ -401,6 +402,26 @@ TEST(DataLayout, ParsePointerSpec) {
EXPECT_THAT_EXPECTED(
DataLayout::parse(Str),
FailedWithMessage("index size cannot be larger than the pointer size"));
+
+ // Only 'e', 'u', and 'n' flags are valid.
+ EXPECT_THAT_EXPECTED(
+ DataLayout::parse("pa:32:32"),
+ FailedWithMessage("'a' is not a valid pointer specification flag"));
+ EXPECT_THAT_EXPECTED(
+ DataLayout::parse("puX:32:32"),
+ FailedWithMessage("'X' is not a valid pointer specification flag"));
+ // Flags must be before the address space number.
+ EXPECT_THAT_EXPECTED(
+ DataLayout::parse("p2n:32:32"),
+ FailedWithMessage("address space must be a 24-bit integer"));
+
+ // AS0 cannot be non-integral.
+ for (StringRef Str : {"pe:64:64", "pu:64:64", "pue:64:64", "pe0:64:64",
+ "pu0:64:64", "peu0:64:64"})
+ EXPECT_THAT_EXPECTED(
+ DataLayout::parse(Str),
+ FailedWithMessage(
+ "address space 0 cannot be unstable or have external state"));
}
TEST(DataLayoutTest, ParseNativeIntegersSpec) {
@@ -556,18 +577,127 @@ TEST(DataLayout, GetPointerPrefAlignment) {
}
TEST(DataLayout, IsNonIntegralAddressSpace) {
- DataLayout Default;
- EXPECT_THAT(Default.getNonIntegralAddressSpaces(), ::testing::SizeIs(0));
+ const DataLayout Default;
+ EXPECT_THAT(Default.getNonStandardAddressSpaces(), ::testing::SizeIs(0));
EXPECT_FALSE(Default.isNonIntegralAddressSpace(0));
EXPECT_FALSE(Default.isNonIntegralAddressSpace(1));
- DataLayout Custom = cantFail(DataLayout::parse("ni:2:16777215"));
- EXPECT_THAT(Custom.getNonIntegralAddressSpaces(),
+ const DataLayout Custom = cantFail(DataLayout::parse("ni:2:16777215"));
+ EXPECT_THAT(Custom.getNonStandardAddressSpaces(),
::testing::ElementsAreArray({2U, 16777215U}));
EXPECT_FALSE(Custom.isNonIntegralAddressSpace(0));
EXPECT_FALSE(Custom.isNonIntegralAddressSpace(1));
EXPECT_TRUE(Custom.isNonIntegralAddressSpace(2));
+ EXPECT_TRUE(Custom.mustNotIntroduceIntToPtr(2));
+ EXPECT_TRUE(Custom.mustNotIntroducePtrToInt(2));
EXPECT_TRUE(Custom.isNonIntegralAddressSpace(16777215));
+ EXPECT_TRUE(Custom.mustNotIntroduceIntToPtr(16777215));
+ EXPECT_TRUE(Custom.mustNotIntroducePtrToInt(16777215));
+
+ // Pointers are marked as non-integral if the address size != total size
+ for (const auto *Layout : {"p2:64:64:64:32", "p2:128:64:64:64"}) {
+ const DataLayout DL = cantFail(DataLayout::parse(Layout));
+ EXPECT_TRUE(DL.isNonIntegralAddressSpace(2));
+ EXPECT_FALSE(DL.hasUnstableRepresentation(2));
+ EXPECT_FALSE(DL.hasExternalState(2));
+ EXPECT_FALSE(DL.mustNotIntroduceIntToPtr(2));
+ EXPECT_FALSE(DL.mustNotIntroducePtrToInt(2));
+ EXPECT_THAT(DL.getNonStandardAddressSpaces(),
+ ::testing::ElementsAreArray({2U}));
+ }
+ // Pointers can be marked as unstable using 'pu'
+ for (const auto *Layout : {"pu2:64:64:64:64", "pu2:64:64:64:32"}) {
+ const DataLayout DL = cantFail(DataLayout::parse(Layout));
+ // Note: isNonIntegralAddressSpace returns true for even with index ==
+ EXPECT_TRUE(DL.isNonIntegralAddressSpace(2));
+ EXPECT_TRUE(DL.hasUnstableRepresentation(2));
+ EXPECT_FALSE(DL.hasExternalState(2));
+ EXPECT_TRUE(DL.mustNotIntroducePtrToInt(2));
+ EXPECT_TRUE(DL.mustNotIntroduceIntToPtr(2));
+ EXPECT_THAT(DL.getNonStandardAddressSpaces(),
+ ::testing::ElementsAreArray({2U}));
+ }
+
+ // Non-integral pointers with external state ('e' flag).
+ for (const auto *Layout : {"pe2:64:64:64:32", "pe2:64:64:64:64"}) {
+ const DataLayout DL = cantFail(DataLayout::parse(Layout));
+ EXPECT_TRUE(DL.isNonIntegralAddressSpace(2));
+ EXPECT_TRUE(DL.hasExternalState(2));
+ EXPECT_TRUE(DL.mustNotIntroduceIntToPtr(2));
+ EXPECT_FALSE(DL.mustNotIntroducePtrToInt(2));
+ EXPECT_FALSE(DL.hasUnstableRepresentation(2));
+ EXPECT_THAT(DL.getNonStandardAddressSpaces(),
+ ::testing::ElementsAreArray({2U}));
+ }
+
+ // It is also possible to have both unstable representation and external state
+ for (const auto *Layout : {"peu2:64:64:64:32", "pue2:128:64:64:64"}) {
+ const DataLayout DL = cantFail(DataLayout::parse(Layout));
+ EXPECT_TRUE(DL.isNonIntegralAddressSpace(2));
+ EXPECT_TRUE(DL.hasExternalState(2));
+ EXPECT_TRUE(Custom.mustNotIntroduceIntToPtr(2));
+ EXPECT_TRUE(Custom.mustNotIntroducePtrToInt(2));
+ EXPECT_TRUE(DL.hasUnstableRepresentation(2));
+ EXPECT_THAT(DL.getNonStandardAddressSpaces(),
+ ::testing::ElementsAreArray({2U}));
+ }
+
+ // For backwards compatibility, the ni DataLayout part overrides any
+ // p[e][u].
+ for (const auto *Layout :
+ {"ni:2-p2:64:64:64:32", "ni:2-pu2:64:64:64:32", "ni:2-pu2:64:64:64:32",
+ "p2:64:64:64:32-ni:2", "pu2:64:64:64:32-ni:2", "pe2:64:64:64:32-ni:2",
+ "peeee2:64:64:64:32-pu2:64:64:64:32-ni:2"}) {
+ DataLayout DL = cantFail(DataLayout::parse(Layout));
+ EXPECT_TRUE(DL.isNonIntegralAddressSpace(2));
+ EXPECT_TRUE(DL.hasUnstableRepresentation(2));
+ // The external state property is new and not expected for existing uses of
+ // non-integral pointers, so existing :ni data layouts should not set it.
+ EXPECT_FALSE(DL.hasExternalState(2));
+ EXPECT_THAT(DL.getNonStandardAddressSpaces(),
+ ::testing::ElementsAreArray({2U}));
+ }
+}
+
+TEST(DataLayout, NonIntegralHelpers) {
+ DataLayout DL = cantFail(DataLayout::parse(
+ "p1:128:128:128:64-pu2:32:32:32:32-pu3:64:64:64:32-pe4:64:64:64:32"));
+ EXPECT_THAT(DL.getNonStandardAddressSpaces(),
+ ::testing::ElementsAreArray({1u, 2u, 3u, 4u}));
+ struct Result {
+ unsigned Addrspace;
+ bool NonIntegral;
+ bool Unstable;
+ bool ExternalState;
+ unsigned Size;
+ } ExpectedResults[] = {
+ {0, false, false, false, 64}, {1, true, false, false, 128},
+ {2, true, true, false, 32}, {3, true, true, false, 64},
+ {4, true, false, true, 64},
+ };
+ LLVMContext Ctx;
+ for (const auto &Exp : ExpectedResults) {
+ EXPECT_EQ(Exp.NonIntegral, DL.isNonIntegralAddressSpace(Exp.Addrspace));
+ EXPECT_EQ(Exp.Unstable, DL.hasUnstableRepresentation(Exp.Addrspace));
+ EXPECT_EQ(Exp.ExternalState, DL.hasExternalState(Exp.Addrspace));
+ bool AvoidIntToPtr = Exp.Unstable || Exp.ExternalState;
+ EXPECT_EQ(AvoidIntToPtr, DL.mustNotIntroduceIntToPtr(Exp.Addrspace));
+ bool AvoidPtrToInt = Exp.Unstable;
+ EXPECT_EQ(AvoidPtrToInt, DL.mustNotIntroducePtrToInt(Exp.Addrspace));
+ Type *PtrTy = PointerType::get(Ctx, Exp.Addrspace);
+ Type *PtrVecTy = VectorType::get(PtrTy, 2, /*Scalable=*/false);
+ Type *ScalablePtrVecTy = VectorType::get(PtrTy, 1, /*Scalable=*/true);
+ for (Type *Ty : {PtrTy, PtrVecTy, ScalablePtrVecTy}) {
+ EXPECT_EQ(AvoidPtrToInt, DL.mustNotIntroducePtrToInt(Ty));
+ EXPECT_EQ(AvoidIntToPtr, DL.mustNotIntroduceIntToPtr(Ty));
+ // The old API should return true for both unstable and non-integral.
+ EXPECT_EQ(Exp.Unstable || Exp.NonIntegral,
+ DL.isNonIntegralPointerType(Ty));
+ }
+ // Both helpers gracefully handle non-pointer, non-vector-of-pointers:
+ EXPECT_FALSE(DL.mustNotIntroducePtrToInt(IntegerType::getInt1Ty(Ctx)));
+ EXPECT_FALSE(DL.mustNotIntroduceIntToPtr(IntegerType::getInt1Ty(Ctx)));
+ }
}
TEST(DataLayoutTest, CopyAssignmentInvalidatesStructLayout) {