[SVE] Replace / operator in TypeSize/ElementCount with divideCoefficientBy

After some recent upstream discussion we decided that it was best
to avoid having the / operator for both ElementCount and TypeSize,
since this could give the impression that these classes can be used
in the same way as basic integer integer types. However, division
for scalable types is a bit odd because we are only dividing the
minimum quantity by a value, as opposed to something like:

  (MinSize * Vscale) / SomeValue

This is why when performing division it's important the caller
first establishes whether the operation makes sense, perhaps by
calling isKnownMultipleOf() prior to division. The caller must now
explictly call divideCoefficientBy() on the class to perform the
operation.

Differential Revision: https://reviews.llvm.org/D87700
This commit is contained in:
David Sherwood 2020-09-11 15:17:08 +01:00
parent e87c3b7d7a
commit 0927cfa9f6
10 changed files with 69 additions and 63 deletions

View File

@ -414,7 +414,16 @@ namespace llvm {
EVT EltVT = getVectorElementType();
auto EltCnt = getVectorElementCount();
assert(EltCnt.isKnownEven() && "Splitting vector, but not in half!");
return EVT::getVectorVT(Context, EltVT, EltCnt / 2);
return EVT::getVectorVT(Context, EltVT, EltCnt.divideCoefficientBy(2));
}
// Return a VT for a vector type with the same element type but
// double the number of elements. The type returned may be an
// extended type.
EVT getDoubleNumVectorElementsVT(LLVMContext &Context) const {
EVT EltVT = getVectorElementType();
auto EltCnt = getVectorElementCount();
return EVT::getVectorVT(Context, EltVT, EltCnt * 2);
}
/// Returns true if the given vector is a power of 2.

View File

@ -504,7 +504,8 @@ public:
auto EltCnt = VTy->getElementCount();
assert(EltCnt.isKnownEven() &&
"Cannot halve vector with odd number of elements.");
return VectorType::get(VTy->getElementType(), EltCnt/2);
return VectorType::get(VTy->getElementType(),
EltCnt.divideCoefficientBy(2));
}
/// This static method returns a VectorType with twice as many elements as the

View File

@ -425,7 +425,7 @@ namespace llvm {
MVT EltVT = getVectorElementType();
auto EltCnt = getVectorElementCount();
assert(EltCnt.isKnownEven() && "Splitting vector, but not in half!");
return getVectorVT(EltVT, EltCnt / 2);
return getVectorVT(EltVT, EltCnt.divideCoefficientBy(2));
}
/// Returns true if the given vector is a power of 2.

View File

@ -44,10 +44,6 @@ public:
ElementCount operator*(unsigned RHS) {
return { Min * RHS, Scalable };
}
ElementCount operator/(unsigned RHS) {
assert(Min % RHS == 0 && "Min is not a multiple of RHS.");
return { Min / RHS, Scalable };
}
friend ElementCount operator-(const ElementCount &LHS,
const ElementCount &RHS) {
@ -70,15 +66,24 @@ public:
return *this;
}
ElementCount &operator/=(unsigned RHS) {
Min /= RHS;
return *this;
/// We do not provide the '/' operator here because division for polynomial
/// types does not work in the same way as for normal integer types. We can
/// only divide the minimum value (or coefficient) by RHS, which is not the
/// same as
/// (Min * Vscale) / RHS
/// The caller is recommended to use this function in combination with
/// isKnownMultipleOf(RHS), which lets the caller know if it's possible to
/// perform a lossless divide by RHS.
ElementCount divideCoefficientBy(unsigned RHS) const {
return ElementCount(Min / RHS, Scalable);
}
ElementCount NextPowerOf2() const {
return {(unsigned)llvm::NextPowerOf2(Min), Scalable};
}
/// This function tells the caller whether the element count is known at
/// compile time to be a multiple of the scalar value RHS.
bool isKnownMultipleOf(unsigned RHS) const {
return Min % RHS == 0;
}
@ -234,8 +239,16 @@ public:
return { LHS * RHS.MinSize, RHS.IsScalable };
}
TypeSize operator/(unsigned RHS) const {
return { MinSize / RHS, IsScalable };
/// We do not provide the '/' operator here because division for polynomial
/// types does not work in the same way as for normal integer types. We can
/// only divide the minimum value (or coefficient) by RHS, which is not the
/// same as
/// (MinSize * Vscale) / RHS
/// The caller is recommended to use this function in combination with
/// isKnownMultipleOf(RHS), which lets the caller know if it's possible to
/// perform a lossless divide by RHS.
TypeSize divideCoefficientBy(uint64_t RHS) const {
return {MinSize / RHS, IsScalable};
}
TypeSize &operator-=(TypeSize RHS) {
@ -258,18 +271,6 @@ public:
return {LHS.MinSize - RHS.MinSize, LHS.IsScalable};
}
friend TypeSize operator/(const TypeSize &LHS, const TypeSize &RHS) {
assert(LHS.IsScalable == RHS.IsScalable &&
"Arithmetic using mixed scalable and fixed types");
return {LHS.MinSize / RHS.MinSize, LHS.IsScalable};
}
friend TypeSize operator%(const TypeSize &LHS, const TypeSize &RHS) {
assert(LHS.IsScalable == RHS.IsScalable &&
"Arithmetic using mixed scalable and fixed types");
return {LHS.MinSize % RHS.MinSize, LHS.IsScalable};
}
// Return the minimum size with the assumption that the size is exact.
// Use in places where a scalable size doesn't make sense (e.g. non-vector
// types, or vectors in backends which don't support scalable vectors).
@ -301,6 +302,10 @@ public:
// Returns true if the type size is zero.
bool isZero() const { return MinSize == 0; }
/// This function tells the caller whether the type size is known at
/// compile time to be a multiple of the scalar value RHS.
bool isKnownMultipleOf(uint64_t RHS) const { return MinSize % RHS == 0; }
// Casts to a uint64_t if this is a fixed-width size.
//
// This interface is deprecated and will be removed in a future version
@ -357,18 +362,6 @@ public:
return { LHS * RHS.MinSize, RHS.IsScalable };
}
TypeSize operator/(uint64_t RHS) const {
return { MinSize / RHS, IsScalable };
}
TypeSize operator/(int RHS) const {
return { MinSize / RHS, IsScalable };
}
TypeSize operator/(int64_t RHS) const {
return { MinSize / RHS, IsScalable };
}
TypeSize NextPowerOf2() const {
return TypeSize(llvm::NextPowerOf2(MinSize), IsScalable);
}

View File

@ -19522,8 +19522,9 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) {
}
if ((DestNumElts % SrcNumElts) == 0) {
unsigned DestSrcRatio = DestNumElts / SrcNumElts;
if ((NVT.getVectorMinNumElements() % DestSrcRatio) == 0) {
ElementCount NewExtEC = NVT.getVectorElementCount() / DestSrcRatio;
if (NVT.getVectorElementCount().isKnownMultipleOf(DestSrcRatio)) {
ElementCount NewExtEC =
NVT.getVectorElementCount().divideCoefficientBy(DestSrcRatio);
EVT ScalarVT = SrcVT.getScalarType();
if ((ExtIdx % DestSrcRatio) == 0) {
SDLoc DL(N);
@ -20690,7 +20691,8 @@ SDValue DAGCombiner::visitINSERT_SUBVECTOR(SDNode *N) {
} else if ((N1SrcSVT.getSizeInBits() % EltSizeInBits) == 0) {
unsigned Scale = N1SrcSVT.getSizeInBits() / EltSizeInBits;
if (NumElts.isKnownMultipleOf(Scale) && (InsIdx % Scale) == 0) {
NewVT = EVT::getVectorVT(Ctx, N1SrcSVT, NumElts / Scale);
NewVT = EVT::getVectorVT(Ctx, N1SrcSVT,
NumElts.divideCoefficientBy(Scale));
NewIdx = DAG.getVectorIdxConstant(InsIdx / Scale, DL);
}
}

View File

@ -2636,7 +2636,7 @@ SDValue DAGTypeLegalizer::SplitVecOp_TruncateHelper(SDNode *N) {
EVT::getFloatingPointVT(InElementSize/2) :
EVT::getIntegerVT(*DAG.getContext(), InElementSize/2);
EVT HalfVT = EVT::getVectorVT(*DAG.getContext(), HalfElementVT,
NumElements/2);
NumElements.divideCoefficientBy(2));
SDValue HalfLo;
SDValue HalfHi;
@ -5060,11 +5060,12 @@ SDValue DAGTypeLegalizer::GenWidenVectorLoads(SmallVectorImpl<SDValue> &LdChain,
EVT NewLdTy = LdOps[i].getValueType();
if (NewLdTy != LdTy) {
// Create a larger vector.
TypeSize LdTySize = LdTy.getSizeInBits();
TypeSize NewLdTySize = NewLdTy.getSizeInBits();
assert(NewLdTySize.isScalable() == LdTySize.isScalable() &&
NewLdTySize.isKnownMultipleOf(LdTySize.getKnownMinSize()));
unsigned NumOps =
(NewLdTy.getSizeInBits() / LdTy.getSizeInBits()).getKnownMinSize();
assert(
(NewLdTy.getSizeInBits() % LdTy.getSizeInBits()).getKnownMinSize() ==
0);
NewLdTySize.getKnownMinSize() / LdTySize.getKnownMinSize();
SmallVector<SDValue, 16> WidenOps(NumOps);
unsigned j = 0;
for (; j != End-Idx; ++j)
@ -5085,7 +5086,8 @@ SDValue DAGTypeLegalizer::GenWidenVectorLoads(SmallVectorImpl<SDValue> &LdChain,
makeArrayRef(&ConcatOps[Idx], End - Idx));
// We need to fill the rest with undefs to build the vector.
unsigned NumOps = (WidenWidth / LdTy.getSizeInBits()).getKnownMinSize();
unsigned NumOps =
WidenWidth.getKnownMinSize() / LdTy.getSizeInBits().getKnownMinSize();
SmallVector<SDValue, 16> WidenOps(NumOps);
SDValue UndefVal = DAG.getUNDEF(LdTy);
{

View File

@ -831,9 +831,7 @@ TargetLoweringBase::getTypeConversion(LLVMContext &Context, EVT VT) const {
"Promote may not follow Expand or Promote");
if (LA == TypeSplitVector)
return LegalizeKind(LA,
EVT::getVectorVT(Context, SVT.getVectorElementType(),
SVT.getVectorElementCount() / 2));
return LegalizeKind(LA, EVT(SVT).getHalfNumVectorElementsVT(Context));
if (LA == TypeScalarizeVector)
return LegalizeKind(LA, SVT.getVectorElementType());
return LegalizeKind(LA, NVT);
@ -889,7 +887,7 @@ TargetLoweringBase::getTypeConversion(LLVMContext &Context, EVT VT) const {
// <4 x i140> -> <2 x i140>
if (LK.first == TypeExpandInteger)
return LegalizeKind(TypeSplitVector,
EVT::getVectorVT(Context, EltVT, NumElts / 2));
VT.getHalfNumVectorElementsVT(Context));
// Promote the integer element types until a legal vector type is found
// or until the element integer type is too big. If a legal type was not
@ -949,7 +947,8 @@ TargetLoweringBase::getTypeConversion(LLVMContext &Context, EVT VT) const {
}
// Vectors with illegal element types are expanded.
EVT NVT = EVT::getVectorVT(Context, EltVT, VT.getVectorElementCount() / 2);
EVT NVT = EVT::getVectorVT(Context, EltVT,
VT.getVectorElementCount().divideCoefficientBy(2));
return LegalizeKind(TypeSplitVector, NVT);
}
@ -982,7 +981,7 @@ static unsigned getVectorTypeBreakdownMVT(MVT VT, MVT &IntermediateVT,
// scalar.
while (EC.getKnownMinValue() > 1 &&
!TLI->isTypeLegal(MVT::getVectorVT(EltTy, EC))) {
EC /= 2;
EC = EC.divideCoefficientBy(2);
NumVectorRegs <<= 1;
}
@ -1482,7 +1481,7 @@ unsigned TargetLoweringBase::getVectorTypeBreakdown(LLVMContext &Context, EVT VT
// end with a scalar if the target doesn't support vectors.
while (EltCnt.getKnownMinValue() > 1 &&
!isTypeLegal(EVT::getVectorVT(Context, EltTy, EltCnt))) {
EltCnt /= 2;
EltCnt = EltCnt.divideCoefficientBy(2);
NumVectorRegs <<= 1;
}

View File

@ -10598,8 +10598,9 @@ SDValue AArch64TargetLowering::LowerSVEStructLoad(unsigned Intrinsic,
assert(VT.getVectorElementCount().getKnownMinValue() % N == 0 &&
"invalid tuple vector type!");
EVT SplitVT = EVT::getVectorVT(*DAG.getContext(), VT.getVectorElementType(),
VT.getVectorElementCount() / N);
EVT SplitVT =
EVT::getVectorVT(*DAG.getContext(), VT.getVectorElementType(),
VT.getVectorElementCount().divideCoefficientBy(N));
assert(isTypeLegal(SplitVT));
SmallVector<EVT, 5> VTs(N, SplitVT);
@ -14393,9 +14394,7 @@ performSignExtendInRegCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
assert((EltTy == MVT::i8 || EltTy == MVT::i16 || EltTy == MVT::i32) &&
"Sign extending from an invalid type");
EVT ExtVT = EVT::getVectorVT(*DAG.getContext(),
VT.getVectorElementType(),
VT.getVectorElementCount() * 2);
EVT ExtVT = VT.getDoubleNumVectorElementsVT(*DAG.getContext());
SDValue Ext = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, ExtOp.getValueType(),
ExtOp, DAG.getValueType(ExtVT));

View File

@ -61,9 +61,10 @@ TEST(ScalableVectorMVTsTest, HelperFuncs) {
EXPECT_EQ(Vnx2i32.widenIntegerVectorElementType(Ctx), Vnx2i64);
EXPECT_EQ(Vnx4i32.getHalfNumVectorElementsVT(Ctx), Vnx2i32);
// Check that overloaded '*' and '/' operators work
// Check that operators work
EXPECT_EQ(EVT::getVectorVT(Ctx, MVT::i64, EltCnt * 2), MVT::nxv4i64);
EXPECT_EQ(EVT::getVectorVT(Ctx, MVT::i64, EltCnt / 2), MVT::nxv1i64);
EXPECT_EQ(EVT::getVectorVT(Ctx, MVT::i64, EltCnt.divideCoefficientBy(2)),
MVT::nxv1i64);
// Check that float->int conversion works
EVT Vnx2f64 = EVT::getVectorVT(Ctx, MVT::f64, ElementCount::getScalable(2));

View File

@ -71,8 +71,8 @@ TEST(VectorTypesTest, FixedLength) {
EXPECT_EQ(V4Int64Ty->getNumElements(), 4U);
EXPECT_EQ(V4Int64Ty->getElementType()->getScalarSizeInBits(), 64U);
auto *V2Int64Ty =
dyn_cast<FixedVectorType>(VectorType::get(Int64Ty, EltCnt / 2));
auto *V2Int64Ty = dyn_cast<FixedVectorType>(
VectorType::get(Int64Ty, EltCnt.divideCoefficientBy(2)));
ASSERT_NE(nullptr, V2Int64Ty);
EXPECT_EQ(V2Int64Ty->getNumElements(), 2U);
EXPECT_EQ(V2Int64Ty->getElementType()->getScalarSizeInBits(), 64U);
@ -166,8 +166,8 @@ TEST(VectorTypesTest, Scalable) {
EXPECT_EQ(ScV4Int64Ty->getMinNumElements(), 4U);
EXPECT_EQ(ScV4Int64Ty->getElementType()->getScalarSizeInBits(), 64U);
auto *ScV2Int64Ty =
dyn_cast<ScalableVectorType>(VectorType::get(Int64Ty, EltCnt / 2));
auto *ScV2Int64Ty = dyn_cast<ScalableVectorType>(
VectorType::get(Int64Ty, EltCnt.divideCoefficientBy(2)));
ASSERT_NE(nullptr, ScV2Int64Ty);
EXPECT_EQ(ScV2Int64Ty->getMinNumElements(), 2U);
EXPECT_EQ(ScV2Int64Ty->getElementType()->getScalarSizeInBits(), 64U);