diff --git a/llvm/include/llvm/Support/Alignment.h b/llvm/include/llvm/Support/Alignment.h --- a/llvm/include/llvm/Support/Alignment.h +++ b/llvm/include/llvm/Support/Alignment.h @@ -49,6 +49,7 @@ friend bool operator>=(Align Lhs, Align Rhs); friend bool operator<(Align Lhs, Align Rhs); friend bool operator>(Align Lhs, Align Rhs); + friend Align maxAlignment(Align LHS, Align RHS); friend unsigned encode(struct MaybeAlign A); friend struct MaybeAlign decodeMaybeAlign(unsigned Value); @@ -214,6 +215,11 @@ return Align(MinAlign(A.value(), Offset)); } +/// Return the more larger of the two alignments. +inline Align maxAlignment(Align LHS, Align RHS) { + return LHS.ShiftValue > RHS.ShiftValue ? LHS : RHS; +} + /// Returns a representation of the alignment that encodes undefined as 0. inline unsigned encode(MaybeAlign A) { return A ? A->ShiftValue + 1 : 0; } 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 @@ -803,8 +803,16 @@ 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) { + if (!abi_or_pref) + return 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 (auto VTy = dyn_cast(Ty)) + return maxAlignment(I->ABIAlign, + getAlignment(VTy->getElementType(), abi_or_pref)); + } // 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,52 @@ 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("f16:16:16-f32:32:32-v64:8:8-v128:8:8"); + EXPECT_THAT_EXPECTED(DL, Succeeded()); + + // 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(Align(1), DL->getPrefTypeAlign(V4F32)); + EXPECT_EQ(Align(1), DL->getPrefTypeAlign(V4F16)); + } + + { + Expected DL = DataLayout::parse("v64:8:8-v128:8:8"); + EXPECT_THAT_EXPECTED(DL, Succeeded()); + + // 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(Align(1), DL->getPrefTypeAlign(V4F32)); + EXPECT_EQ(Align(1), DL->getPrefTypeAlign(V4F16)); + } + + { + Expected DL = DataLayout::parse(""); + EXPECT_THAT_EXPECTED(DL, Succeeded()); + + // The alignment for a vector type larger than any specified vector type + // uses the natural alignment as a fallback. + EXPECT_EQ(Align(4 * 4), DL->getABITypeAlign(V4F32)); + EXPECT_EQ(Align(4 * 2), DL->getABITypeAlign(V4F16)); + + EXPECT_EQ(Align(4 * 4), DL->getPrefTypeAlign(V4F32)); + EXPECT_EQ(Align(4 * 2), DL->getPrefTypeAlign(V4F16)); + } +} + } // anonymous namespace