diff --git a/llvm/include/llvm/IR/DataLayout.h b/llvm/include/llvm/IR/DataLayout.h index 85dae10883c67..2f06bda6c30a5 100644 --- a/llvm/include/llvm/IR/DataLayout.h +++ b/llvm/include/llvm/IR/DataLayout.h @@ -115,14 +115,6 @@ class DataLayout { // FIXME: `unsigned char` truncates the value parsed by `parseSpecifier`. SmallVector LegalIntWidths; - /// Type specifier used by some internal functions. - enum class TypeSpecifier { - Integer = 'i', - Float = 'f', - Vector = 'v', - Aggregate = 'a' - }; - /// Primitive type specifications. Sorted and uniqued by type bit width. SmallVector IntSpecs; SmallVector FloatSpecs; @@ -145,10 +137,9 @@ class DataLayout { /// well-defined bitwise representation. SmallVector NonIntegralAddressSpaces; - /// Attempts to set the specification for the given type. - /// Returns an error description on failure. - Error setPrimitiveSpec(TypeSpecifier Specifier, uint32_t BitWidth, - Align ABIAlign, Align PrefAlign); + /// Sets or updates the specification for the given primitive type. + void setPrimitiveSpec(char Specifier, uint32_t BitWidth, Align ABIAlign, + Align PrefAlign); /// Searches for a pointer specification that matches the given address space. /// Returns the default address space specification if not found. @@ -164,7 +155,13 @@ class DataLayout { /// Internal helper method that returns requested alignment for type. Align getAlignment(Type *Ty, bool abi_or_pref) const; - /// Attempts to parse a pointer specification ('p'). + /// Attempts to parse primitive specification ('i', 'f', or 'v'). + Error parsePrimitiveSpec(StringRef Spec); + + /// Attempts to parse aggregate specification ('a'). + Error parseAggregateSpec(StringRef Spec); + + /// Attempts to parse pointer specification ('p'). Error parsePointerSpec(StringRef Spec); /// Attempts to parse a single specification. diff --git a/llvm/lib/IR/DataLayout.cpp b/llvm/lib/IR/DataLayout.cpp index 425a9024c897d..5efdaaccf1fc7 100644 --- a/llvm/lib/IR/DataLayout.cpp +++ b/llvm/lib/IR/DataLayout.cpp @@ -376,6 +376,82 @@ static Error getAddrSpace(StringRef R, unsigned &AddrSpace) { return Error::success(); } +Error DataLayout::parsePrimitiveSpec(StringRef Spec) { + // [ifv]:[:] + SmallVector Components; + char Specifier = Spec.front(); + assert(Specifier == 'i' || Specifier == 'f' || Specifier == 'v'); + Spec.drop_front().split(Components, ':'); + + if (Components.size() < 2 || Components.size() > 3) + return createSpecFormatError(Twine(Specifier) + ":[:]"); + + // Size. Required, cannot be zero. + unsigned BitWidth; + if (Error Err = parseSize(Components[0], BitWidth)) + return Err; + + // ABI alignment. + Align ABIAlign; + if (Error Err = parseAlignment(Components[1], ABIAlign, "ABI")) + return Err; + + if (Specifier == 'i' && BitWidth == 8 && ABIAlign != 1) + return createStringError("i8 must be 8-bit aligned"); + + // Preferred alignment. Optional, defaults to the ABI alignment. + Align PrefAlign = ABIAlign; + if (Components.size() > 2) + if (Error Err = parseAlignment(Components[2], PrefAlign, "preferred")) + return Err; + + if (PrefAlign < ABIAlign) + return createStringError( + "preferred alignment cannot be less than the ABI alignment"); + + setPrimitiveSpec(Specifier, BitWidth, ABIAlign, PrefAlign); + return Error::success(); +} + +Error DataLayout::parseAggregateSpec(StringRef Spec) { + // a:[:] + SmallVector Components; + assert(Spec.front() == 'a'); + Spec.drop_front().split(Components, ':'); + + if (Components.size() < 2 || Components.size() > 3) + return createSpecFormatError("a:[:]"); + + // According to LangRef, component must be absent altogether. + // For backward compatibility, allow it to be specified, but require + // it to be zero. + if (!Components[0].empty()) { + unsigned BitWidth; + if (!to_integer(Components[0], BitWidth, 10) || BitWidth != 0) + return createStringError("size must be zero"); + } + + // ABI alignment. Required. Can be zero, meaning use one byte alignment. + Align ABIAlign; + if (Error Err = + parseAlignment(Components[1], ABIAlign, "ABI", /*AllowZero=*/true)) + return Err; + + // Preferred alignment. Optional, defaults to the ABI alignment. + Align PrefAlign = ABIAlign; + if (Components.size() > 2) + if (Error Err = parseAlignment(Components[2], PrefAlign, "preferred")) + return Err; + + if (PrefAlign < ABIAlign) + return createStringError( + "preferred alignment cannot be less than the ABI alignment"); + + StructABIAlignment = ABIAlign; + StructPrefAlignment = PrefAlign; + return Error::success(); +} + Error DataLayout::parsePointerSpec(StringRef Spec) { // p[]::[:[:]] SmallVector Components; @@ -451,6 +527,12 @@ Error DataLayout::parseSpecification(StringRef Spec) { assert(!Spec.empty() && "Empty specification is handled by the caller"); char Specifier = Spec.front(); + if (Specifier == 'i' || Specifier == 'f' || Specifier == 'v') + return parsePrimitiveSpec(Spec); + + if (Specifier == 'a') + return parseAggregateSpec(Spec); + if (Specifier == 'p') return parsePointerSpec(Spec); @@ -477,78 +559,6 @@ Error DataLayout::parseSpecification(StringRef Spec) { case 'e': BigEndian = false; break; - case 'i': - case 'v': - case 'f': - case 'a': { - TypeSpecifier Specifier; - switch (SpecifierChar) { - default: - llvm_unreachable("Unexpected specifier!"); - case 'i': - Specifier = TypeSpecifier::Integer; - break; - case 'v': - Specifier = TypeSpecifier::Vector; - break; - case 'f': - Specifier = TypeSpecifier::Float; - break; - case 'a': - Specifier = TypeSpecifier::Aggregate; - break; - } - - // Bit size. - unsigned Size = 0; - if (!Tok.empty()) - if (Error Err = getInt(Tok, Size)) - return Err; - - if (Specifier == TypeSpecifier::Aggregate && Size != 0) - return reportError("Sized aggregate specification in datalayout string"); - - // ABI alignment. - if (Rest.empty()) - return reportError( - "Missing alignment specification in datalayout string"); - if (Error Err = ::split(Rest, ':', Split)) - return Err; - unsigned ABIAlign; - if (Error Err = getIntInBytes(Tok, ABIAlign)) - return Err; - if (Specifier != TypeSpecifier::Aggregate && !ABIAlign) - return reportError( - "ABI alignment specification must be >0 for non-aggregate types"); - - if (!isUInt<16>(ABIAlign)) - return reportError("Invalid ABI alignment, must be a 16bit integer"); - if (ABIAlign != 0 && !isPowerOf2_64(ABIAlign)) - return reportError("Invalid ABI alignment, must be a power of 2"); - if (Specifier == TypeSpecifier::Integer && Size == 8 && ABIAlign != 1) - return reportError("Invalid ABI alignment, i8 must be naturally aligned"); - - // Preferred alignment. - unsigned PrefAlign = ABIAlign; - if (!Rest.empty()) { - if (Error Err = ::split(Rest, ':', Split)) - return Err; - if (Error Err = getIntInBytes(Tok, PrefAlign)) - return Err; - } - - if (!isUInt<16>(PrefAlign)) - return reportError( - "Invalid preferred alignment, must be a 16bit integer"); - if (PrefAlign != 0 && !isPowerOf2_64(PrefAlign)) - return reportError("Invalid preferred alignment, must be a power of 2"); - - if (Error Err = setPrimitiveSpec(Specifier, Size, assumeAligned(ABIAlign), - assumeAligned(PrefAlign))) - return Err; - - break; - } case 'n': // Native integer types. while (true) { unsigned Width; @@ -668,32 +678,19 @@ Error DataLayout::parseLayoutString(StringRef LayoutString) { return Error::success(); } -Error DataLayout::setPrimitiveSpec(TypeSpecifier Specifier, uint32_t BitWidth, - Align ABIAlign, Align PrefAlign) { - // AlignmentsTy::ABIAlign and AlignmentsTy::PrefAlign were once stored as - // uint16_t, it is unclear if there are requirements for alignment to be less - // than 2^16 other than storage. In the meantime we leave the restriction as - // an assert. See D67400 for context. - assert(Log2(ABIAlign) < 16 && Log2(PrefAlign) < 16 && "Alignment too big"); - if (!isUInt<24>(BitWidth)) - return reportError("Invalid bit width, must be a 24-bit integer"); - if (PrefAlign < ABIAlign) - return reportError( - "Preferred alignment cannot be less than the ABI alignment"); - +void DataLayout::setPrimitiveSpec(char Specifier, uint32_t BitWidth, + Align ABIAlign, Align PrefAlign) { SmallVectorImpl *Specs; switch (Specifier) { - case TypeSpecifier::Aggregate: - StructABIAlignment = ABIAlign; - StructPrefAlignment = PrefAlign; - return Error::success(); - case TypeSpecifier::Integer: + default: + llvm_unreachable("Unexpected specifier"); + case 'i': Specs = &IntSpecs; break; - case TypeSpecifier::Float: + case 'f': Specs = &FloatSpecs; break; - case TypeSpecifier::Vector: + case 'v': Specs = &VectorSpecs; break; } @@ -707,7 +704,6 @@ Error DataLayout::setPrimitiveSpec(TypeSpecifier Specifier, uint32_t BitWidth, // Insert before I to keep the vector sorted. Specs->insert(I, PrimitiveSpec{BitWidth, ABIAlign, PrefAlign}); } - return Error::success(); } const DataLayout::PointerSpec & diff --git a/llvm/test/Transforms/InstCombine/crash.ll b/llvm/test/Transforms/InstCombine/crash.ll index 5f86069ef7368..9b37d6943b9e5 100644 --- a/llvm/test/Transforms/InstCombine/crash.ll +++ b/llvm/test/Transforms/InstCombine/crash.ll @@ -1,5 +1,5 @@ ; RUN: opt < %s -passes=instcombine -S -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128:n8:16:32" +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32" target triple = "i386-apple-darwin10.0" define i32 @test0(i8 %tmp2) ssp { diff --git a/llvm/test/Transforms/InstCombine/phi.ll b/llvm/test/Transforms/InstCombine/phi.ll index b12982dd27e40..2673b1d74bb6f 100644 --- a/llvm/test/Transforms/InstCombine/phi.ll +++ b/llvm/test/Transforms/InstCombine/phi.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -passes=instcombine -S | FileCheck %s -target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128:n8:16:32:64" +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" define i32 @test1(i32 %A, i1 %b) { ; CHECK-LABEL: @test1( diff --git a/llvm/unittests/IR/DataLayoutTest.cpp b/llvm/unittests/IR/DataLayoutTest.cpp index 4b236b2d165f9..9464b489b65f4 100644 --- a/llvm/unittests/IR/DataLayoutTest.cpp +++ b/llvm/unittests/IR/DataLayoutTest.cpp @@ -19,6 +19,8 @@ using namespace llvm; namespace { +class DataLayoutTest : public ::testing::Test {}; + // TODO: Split into multiple TESTs. TEST(DataLayoutTest, ParseErrors) { EXPECT_THAT_EXPECTED( @@ -30,12 +32,6 @@ TEST(DataLayoutTest, ParseErrors) { EXPECT_THAT_EXPECTED( DataLayout::parse("n0"), FailedWithMessage("Zero width native integer type in datalayout string")); - EXPECT_THAT_EXPECTED( - DataLayout::parse("a1:64"), - FailedWithMessage("Sized aggregate specification in datalayout string")); - EXPECT_THAT_EXPECTED( - DataLayout::parse("a:"), - FailedWithMessage("Trailing separator in datalayout string")); EXPECT_THAT_EXPECTED( DataLayout::parse("m"), FailedWithMessage("Expected mangling specifier in datalayout string")); @@ -43,38 +39,10 @@ TEST(DataLayoutTest, ParseErrors) { DataLayout::parse("m."), FailedWithMessage("Unexpected trailing characters after mangling " "specifier in datalayout string")); - EXPECT_THAT_EXPECTED( - DataLayout::parse("f"), - FailedWithMessage( - "Missing alignment specification in datalayout string")); EXPECT_THAT_EXPECTED( DataLayout::parse(":32"), FailedWithMessage( "Expected token before separator in datalayout string")); - EXPECT_THAT_EXPECTED( - DataLayout::parse("i64:64:16"), - FailedWithMessage( - "Preferred alignment cannot be less than the ABI alignment")); - EXPECT_THAT_EXPECTED( - DataLayout::parse("i64:16:16777216"), - FailedWithMessage( - "Invalid preferred alignment, must be a 16bit integer")); - EXPECT_THAT_EXPECTED( - DataLayout::parse("i64:16777216:16777216"), - FailedWithMessage("Invalid ABI alignment, must be a 16bit integer")); - EXPECT_THAT_EXPECTED( - DataLayout::parse("i16777216:16:16"), - FailedWithMessage("Invalid bit width, must be a 24-bit integer")); - EXPECT_THAT_EXPECTED( - DataLayout::parse("v128:0:128"), - FailedWithMessage( - "ABI alignment specification must be >0 for non-aggregate types")); - EXPECT_THAT_EXPECTED( - DataLayout::parse("i32:24:32"), - FailedWithMessage("Invalid ABI alignment, must be a power of 2")); - EXPECT_THAT_EXPECTED( - DataLayout::parse("i32:32:24"), - FailedWithMessage("Invalid preferred alignment, must be a power of 2")); EXPECT_THAT_EXPECTED( DataLayout::parse("A16777216"), FailedWithMessage("Invalid address space, must be a 24-bit integer")); @@ -87,9 +55,6 @@ TEST(DataLayoutTest, ParseErrors) { EXPECT_THAT_EXPECTED( DataLayout::parse("Fi24"), FailedWithMessage("Alignment is neither 0 nor a power of 2")); - EXPECT_THAT_EXPECTED( - DataLayout::parse("i8:16"), - FailedWithMessage("Invalid ABI alignment, i8 must be naturally aligned")); EXPECT_THAT_EXPECTED( DataLayout::parse("S24"), FailedWithMessage("Alignment is neither 0 nor a power of 2")); @@ -105,6 +70,165 @@ TEST(DataLayout, LayoutStringFormat) { FailedWithMessage("empty specification is not allowed")); } +class DataLayoutPrimitiveSpecificationTest + : public DataLayoutTest, + public ::testing::WithParamInterface { + char Specifier; + +public: + DataLayoutPrimitiveSpecificationTest() : Specifier(GetParam()) {} + + std::string format(StringRef Str) const { + std::string Res = Str.str(); + std::replace(Res.begin(), Res.end(), '!', Specifier); + return Res; + } +}; + +INSTANTIATE_TEST_SUITE_P(PrmitiveSpecifiers, + DataLayoutPrimitiveSpecificationTest, + ::testing::Values('i', 'f', 'v')); + +TEST_P(DataLayoutPrimitiveSpecificationTest, ParsePrimitiveSpec) { + for (StringRef Str : + {"!1:16", "!8:8:8", "!16:32:64", "!16777215:32768:32768"}) + EXPECT_THAT_EXPECTED(DataLayout::parse(format(Str)), Succeeded()); + + for (StringRef Str : {"!", "!1", "!32:32:32:32", "!16:32:64:128"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(format(Str)), + FailedWithMessage(format("malformed specification, must be of the form " + "\"!:[:]\""))); + + // size + for (StringRef Str : {"!:8", "!:16:16", "!:32:64"}) + EXPECT_THAT_EXPECTED(DataLayout::parse(format(Str)), + FailedWithMessage("size component cannot be empty")); + + for (StringRef Str : + {"!0:8", "!0x8:8", "!x:8:8", "!0:16:32", "!16777216:64:64"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(format(Str)), + FailedWithMessage("size must be a non-zero 24-bit integer")); + + // ABI alignment + for (StringRef Str : {"!8:", "!16::16", "!32::64"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(format(Str)), + FailedWithMessage("ABI alignment component cannot be empty")); + + for (StringRef Str : {"!1:x", "!8:8x:8", "!16:65536:65536"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(format(Str)), + FailedWithMessage("ABI alignment must be a 16-bit integer")); + + for (StringRef Str : {"!8:0", "!16:0:16", "!32:0:64"}) + EXPECT_THAT_EXPECTED(DataLayout::parse(format(Str)), + FailedWithMessage("ABI alignment must be non-zero")); + + for (StringRef Str : {"!1:1", "!8:4", "!16:6:16", "!32:24:64"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(format(Str)), + FailedWithMessage( + "ABI alignment must be a power of two times the byte width")); + + // preferred alignment + for (StringRef Str : {"!1:8:", "!16:16:", "!64:32:"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(format(Str)), + FailedWithMessage("preferred alignment component cannot be empty")); + + for (StringRef Str : {"!1:8:x", "!8:8:0x8", "!16:32:65536"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(format(Str)), + FailedWithMessage("preferred alignment must be a 16-bit integer")); + + for (StringRef Str : {"!8:8:0", "!32:16:0"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(format(Str)), + FailedWithMessage("preferred alignment must be non-zero")); + + for (StringRef Str : {"!1:8:12", "!8:8:17", "!16:32:40"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(format(Str)), + FailedWithMessage( + "preferred alignment must be a power of two times the byte width")); + + for (StringRef Str : {"!1:16:8", "!64:32:16"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(format(Str)), + FailedWithMessage( + "preferred alignment cannot be less than the ABI alignment")); + + // Additional check for byte-sized integer. + if (GetParam() == 'i') { + for (StringRef Str : {"!8:16", "!8:16:8", "!8:16:32"}) + EXPECT_THAT_EXPECTED(DataLayout::parse(format(Str)), + FailedWithMessage("i8 must be 8-bit aligned")); + } +} + +TEST(DataLayoutTest, ParseAggregateSpec) { + for (StringRef Str : {"a:8", "a:0:16", "a0:32:64", "a:32768:32768"}) + EXPECT_THAT_EXPECTED(DataLayout::parse(Str), Succeeded()); + + for (StringRef Str : {"a", "a0", "a:32:32:32", "a0:32:64:128"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(Str), + FailedWithMessage("malformed specification, must be of the form " + "\"a:[:]\"")); + + // size + for (StringRef Str : {"a1:8", "a0x0:8", "ax:16:32"}) + EXPECT_THAT_EXPECTED(DataLayout::parse(Str), + FailedWithMessage("size must be zero")); + + // ABI alignment + for (StringRef Str : {"a:", "a0:", "a::32"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(Str), + FailedWithMessage("ABI alignment component cannot be empty")); + + for (StringRef Str : {"a:x", "a0:0x0", "a:65536", "a0:65536:65536"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(Str), + FailedWithMessage("ABI alignment must be a 16-bit integer")); + + for (StringRef Str : {"a:1", "a:4", "a:9:16", "a0:24:32"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(Str), + FailedWithMessage( + "ABI alignment must be a power of two times the byte width")); + + // preferred alignment + for (StringRef Str : {"a:8:", "a0:16:", "a0:0:"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(Str), + FailedWithMessage("preferred alignment component cannot be empty")); + + for (StringRef Str : {"a:16:x", "a0:8:0x8", "a:16:65536"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(Str), + FailedWithMessage("preferred alignment must be a 16-bit integer")); + + for (StringRef Str : {"a:0:0", "a0:16:0"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(Str), + FailedWithMessage("preferred alignment must be non-zero")); + + for (StringRef Str : {"a:8:12", "a:16:17", "a0:32:40"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(Str), + FailedWithMessage( + "preferred alignment must be a power of two times the byte width")); + + for (StringRef Str : {"a:16:8", "a0:32:16"}) + EXPECT_THAT_EXPECTED( + DataLayout::parse(Str), + FailedWithMessage( + "preferred alignment cannot be less than the ABI alignment")); +} + TEST(DataLayout, ParsePointerSpec) { for (StringRef Str : {"p:16:8", "p:16:16:64", "p:32:64:64:32", "p0:32:64", "p42:64:32:32", diff --git a/mlir/test/Target/LLVMIR/Import/import-failure.ll b/mlir/test/Target/LLVMIR/Import/import-failure.ll index 9c24ed2b75746..6bde174642d54 100644 --- a/mlir/test/Target/LLVMIR/Import/import-failure.ll +++ b/mlir/test/Target/LLVMIR/Import/import-failure.ll @@ -359,12 +359,6 @@ declare void @llvm.experimental.noalias.scope.decl(metadata) ; // ----- -; CHECK: import-failure.ll -; CHECK-SAME: error: cannot translate data layout: i8:8:8:8 -target datalayout = "e-i8:8:8:8" - -; // ----- - ; CHECK: import-failure.ll ; CHECK-SAME: warning: unhandled data layout token: ni:42 target datalayout = "e-ni:42-i64:64"