diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -2717,6 +2717,10 @@ Specifies that the target lays out data in little-endian form. That is, the bits with the least significance have the lowest address location. +``V`` + Specifies that when resolving vector alignments, if the vector element + type's alignment is greater than the vector alignment, prefer the element + type's alignment. ``S`` Specifies the natural alignment of the stack in bits. Alignment promotion of stack variables is limited to the natural stack diff --git a/llvm/include/llvm/IR/DataLayout.h b/llvm/include/llvm/IR/DataLayout.h --- a/llvm/include/llvm/IR/DataLayout.h +++ b/llvm/include/llvm/IR/DataLayout.h @@ -121,6 +121,7 @@ private: /// Defaults to false. bool BigEndian; + bool ConsidersElementAlignment; unsigned AllocaAddrSpace; MaybeAlign StackNaturalAlign; @@ -214,6 +215,7 @@ clear(); StringRepresentation = DL.StringRepresentation; BigEndian = DL.isBigEndian(); + ConsidersElementAlignment = DL.considersElementAlignment(); AllocaAddrSpace = DL.AllocaAddrSpace; StackNaturalAlign = DL.StackNaturalAlign; FunctionPtrAlign = DL.FunctionPtrAlign; @@ -244,6 +246,10 @@ bool isLittleEndian() const { return !BigEndian; } bool isBigEndian() const { return BigEndian; } + /// Returns true if the data layout considers vector element type alignment + /// when determining vector alignments. + bool considersElementAlignment() const { return ConsidersElementAlignment; } + /// Returns the string representation of the DataLayout. /// /// This representation is in the same format accepted by the string diff --git a/llvm/lib/IR/DataLayout.cpp b/llvm/lib/IR/DataLayout.cpp --- a/llvm/lib/IR/DataLayout.cpp +++ b/llvm/lib/IR/DataLayout.cpp @@ -182,6 +182,7 @@ LayoutMap = nullptr; BigEndian = false; + ConsidersElementAlignment = false; AllocaAddrSpace = 0; StackNaturalAlign.reset(); ProgramAddrSpace = 0; @@ -522,6 +523,9 @@ break; } break; + case 'V': + ConsidersElementAlignment = true; + break; default: return reportError("Unknown specifier in datalayout string"); break; @@ -539,6 +543,7 @@ bool DataLayout::operator==(const DataLayout &Other) const { bool Ret = BigEndian == Other.BigEndian && + ConsidersElementAlignment == Other.ConsidersElementAlignment && AllocaAddrSpace == Other.AllocaAddrSpace && StackNaturalAlign == Other.StackNaturalAlign && ProgramAddrSpace == Other.ProgramAddrSpace && @@ -803,8 +808,17 @@ unsigned BitWidth = getTypeSizeInBits(Ty).getKnownMinSize(); auto I = findAlignmentLowerBound(VECTOR_ALIGN, BitWidth); if (I != Alignments.end() && I->AlignType == VECTOR_ALIGN && - I->TypeBitWidth == BitWidth) - return abi_or_pref ? I->ABIAlign : I->PrefAlign; + I->TypeBitWidth == BitWidth) { + Align VectorAlign = abi_or_pref ? I->ABIAlign : I->PrefAlign; + + // If we have a specified vector alignment the vector ABI should be the + // larger of the vector alignment and the element type's alignment. + if (considersElementAlignment()) + if (auto VTy = dyn_cast(Ty)) + return std::max(VectorAlign, + getAlignment(VTy->getElementType(), abi_or_pref)); + return VectorAlign; + } // By default, use natural alignment for vector types. This is consistent // with what clang and llvm-gcc do. diff --git a/llvm/unittests/IR/DataLayoutTest.cpp b/llvm/unittests/IR/DataLayoutTest.cpp --- a/llvm/unittests/IR/DataLayoutTest.cpp +++ b/llvm/unittests/IR/DataLayoutTest.cpp @@ -104,4 +104,56 @@ EXPECT_EQ(Align(4 * 8), DL->getPrefTypeAlign(V8F32Ty)); } +TEST(DataLayoutTest, VectorAlignElement) { + LLVMContext Context; + Type *const FloatTy = Type::getFloatTy(Context); + Type *const V4F32 = FixedVectorType::get(FloatTy, 4); + Type *const HalfTy = Type::getHalfTy(Context); + Type *const V4F16 = FixedVectorType::get(HalfTy, 4); + + { + Expected DL = + DataLayout::parse("V-f16:16:16-f32:32:32-v64:8:8-v128:8:8"); + EXPECT_THAT_EXPECTED(DL, Succeeded()); + EXPECT_TRUE(DL->considersElementAlignment()); + + // The alignment for a vector type larger than any specified vector type + // uses the natural alignment as a fallback. + EXPECT_EQ(DL->getABITypeAlign(FloatTy), DL->getABITypeAlign(V4F32)); + EXPECT_EQ(DL->getABITypeAlign(HalfTy), DL->getABITypeAlign(V4F16)); + + EXPECT_EQ(DL->getPrefTypeAlign(FloatTy), DL->getPrefTypeAlign(V4F32)); + EXPECT_EQ(DL->getPrefTypeAlign(HalfTy), DL->getPrefTypeAlign(V4F16)); + } + + { + Expected DL = DataLayout::parse("V-v64:8:8-v128:8:8"); + EXPECT_THAT_EXPECTED(DL, Succeeded()); + EXPECT_TRUE(DL->considersElementAlignment()); + + // The alignment for a vector type larger than any specified vector type + // uses the natural alignment as a fallback. + EXPECT_EQ(DL->getABITypeAlign(FloatTy), DL->getABITypeAlign(V4F32)); + EXPECT_EQ(DL->getABITypeAlign(HalfTy), DL->getABITypeAlign(V4F16)); + + EXPECT_EQ(DL->getPrefTypeAlign(FloatTy), DL->getPrefTypeAlign(V4F32)); + EXPECT_EQ(DL->getPrefTypeAlign(HalfTy), DL->getPrefTypeAlign(V4F16)); + } + + { + Expected DL = + DataLayout::parse("f16:16:16-f32:32:32-v64:8:8-v128:8:8"); + EXPECT_THAT_EXPECTED(DL, Succeeded()); + EXPECT_FALSE(DL->considersElementAlignment()); + + // Without the `V` option, the vector alignments from the data layout are + // used regardless of the element alignments. + EXPECT_EQ(Align(1), DL->getABITypeAlign(V4F32)); + EXPECT_EQ(Align(1), DL->getABITypeAlign(V4F16)); + + EXPECT_EQ(Align(1), DL->getPrefTypeAlign(V4F32)); + EXPECT_EQ(Align(1), DL->getPrefTypeAlign(V4F16)); + } +} + } // anonymous namespace