1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[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(); EVT EltVT = getVectorElementType();
auto EltCnt = getVectorElementCount(); auto EltCnt = getVectorElementCount();
assert(EltCnt.isKnownEven() && "Splitting vector, but not in half!"); 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. /// Returns true if the given vector is a power of 2.

View File

@ -504,7 +504,8 @@ public:
auto EltCnt = VTy->getElementCount(); auto EltCnt = VTy->getElementCount();
assert(EltCnt.isKnownEven() && assert(EltCnt.isKnownEven() &&
"Cannot halve vector with odd number of elements."); "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 /// This static method returns a VectorType with twice as many elements as the

View File

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

View File

@ -44,10 +44,6 @@ public:
ElementCount operator*(unsigned RHS) { ElementCount operator*(unsigned RHS) {
return { Min * RHS, Scalable }; 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, friend ElementCount operator-(const ElementCount &LHS,
const ElementCount &RHS) { const ElementCount &RHS) {
@ -70,15 +66,24 @@ public:
return *this; return *this;
} }
ElementCount &operator/=(unsigned RHS) { /// We do not provide the '/' operator here because division for polynomial
Min /= RHS; /// types does not work in the same way as for normal integer types. We can
return *this; /// 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 { ElementCount NextPowerOf2() const {
return {(unsigned)llvm::NextPowerOf2(Min), Scalable}; 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 { bool isKnownMultipleOf(unsigned RHS) const {
return Min % RHS == 0; return Min % RHS == 0;
} }
@ -234,8 +239,16 @@ public:
return { LHS * RHS.MinSize, RHS.IsScalable }; return { LHS * RHS.MinSize, RHS.IsScalable };
} }
TypeSize operator/(unsigned RHS) const { /// We do not provide the '/' operator here because division for polynomial
return { MinSize / RHS, IsScalable }; /// 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) { TypeSize &operator-=(TypeSize RHS) {
@ -258,18 +271,6 @@ public:
return {LHS.MinSize - RHS.MinSize, LHS.IsScalable}; 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. // 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 // 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). // types, or vectors in backends which don't support scalable vectors).
@ -301,6 +302,10 @@ public:
// Returns true if the type size is zero. // Returns true if the type size is zero.
bool isZero() const { return MinSize == 0; } 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. // Casts to a uint64_t if this is a fixed-width size.
// //
// This interface is deprecated and will be removed in a future version // This interface is deprecated and will be removed in a future version
@ -357,18 +362,6 @@ public:
return { LHS * RHS.MinSize, RHS.IsScalable }; 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 { TypeSize NextPowerOf2() const {
return TypeSize(llvm::NextPowerOf2(MinSize), IsScalable); return TypeSize(llvm::NextPowerOf2(MinSize), IsScalable);
} }

View File

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

View File

@ -2636,7 +2636,7 @@ SDValue DAGTypeLegalizer::SplitVecOp_TruncateHelper(SDNode *N) {
EVT::getFloatingPointVT(InElementSize/2) : EVT::getFloatingPointVT(InElementSize/2) :
EVT::getIntegerVT(*DAG.getContext(), InElementSize/2); EVT::getIntegerVT(*DAG.getContext(), InElementSize/2);
EVT HalfVT = EVT::getVectorVT(*DAG.getContext(), HalfElementVT, EVT HalfVT = EVT::getVectorVT(*DAG.getContext(), HalfElementVT,
NumElements/2); NumElements.divideCoefficientBy(2));
SDValue HalfLo; SDValue HalfLo;
SDValue HalfHi; SDValue HalfHi;
@ -5060,11 +5060,12 @@ SDValue DAGTypeLegalizer::GenWidenVectorLoads(SmallVectorImpl<SDValue> &LdChain,
EVT NewLdTy = LdOps[i].getValueType(); EVT NewLdTy = LdOps[i].getValueType();
if (NewLdTy != LdTy) { if (NewLdTy != LdTy) {
// Create a larger vector. // Create a larger vector.
TypeSize LdTySize = LdTy.getSizeInBits();
TypeSize NewLdTySize = NewLdTy.getSizeInBits();
assert(NewLdTySize.isScalable() == LdTySize.isScalable() &&
NewLdTySize.isKnownMultipleOf(LdTySize.getKnownMinSize()));
unsigned NumOps = unsigned NumOps =
(NewLdTy.getSizeInBits() / LdTy.getSizeInBits()).getKnownMinSize(); NewLdTySize.getKnownMinSize() / LdTySize.getKnownMinSize();
assert(
(NewLdTy.getSizeInBits() % LdTy.getSizeInBits()).getKnownMinSize() ==
0);
SmallVector<SDValue, 16> WidenOps(NumOps); SmallVector<SDValue, 16> WidenOps(NumOps);
unsigned j = 0; unsigned j = 0;
for (; j != End-Idx; ++j) for (; j != End-Idx; ++j)
@ -5085,7 +5086,8 @@ SDValue DAGTypeLegalizer::GenWidenVectorLoads(SmallVectorImpl<SDValue> &LdChain,
makeArrayRef(&ConcatOps[Idx], End - Idx)); makeArrayRef(&ConcatOps[Idx], End - Idx));
// We need to fill the rest with undefs to build the vector. // 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); SmallVector<SDValue, 16> WidenOps(NumOps);
SDValue UndefVal = DAG.getUNDEF(LdTy); 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"); "Promote may not follow Expand or Promote");
if (LA == TypeSplitVector) if (LA == TypeSplitVector)
return LegalizeKind(LA, return LegalizeKind(LA, EVT(SVT).getHalfNumVectorElementsVT(Context));
EVT::getVectorVT(Context, SVT.getVectorElementType(),
SVT.getVectorElementCount() / 2));
if (LA == TypeScalarizeVector) if (LA == TypeScalarizeVector)
return LegalizeKind(LA, SVT.getVectorElementType()); return LegalizeKind(LA, SVT.getVectorElementType());
return LegalizeKind(LA, NVT); return LegalizeKind(LA, NVT);
@ -889,7 +887,7 @@ TargetLoweringBase::getTypeConversion(LLVMContext &Context, EVT VT) const {
// <4 x i140> -> <2 x i140> // <4 x i140> -> <2 x i140>
if (LK.first == TypeExpandInteger) if (LK.first == TypeExpandInteger)
return LegalizeKind(TypeSplitVector, return LegalizeKind(TypeSplitVector,
EVT::getVectorVT(Context, EltVT, NumElts / 2)); VT.getHalfNumVectorElementsVT(Context));
// Promote the integer element types until a legal vector type is found // 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 // 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. // 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); return LegalizeKind(TypeSplitVector, NVT);
} }
@ -982,7 +981,7 @@ static unsigned getVectorTypeBreakdownMVT(MVT VT, MVT &IntermediateVT,
// scalar. // scalar.
while (EC.getKnownMinValue() > 1 && while (EC.getKnownMinValue() > 1 &&
!TLI->isTypeLegal(MVT::getVectorVT(EltTy, EC))) { !TLI->isTypeLegal(MVT::getVectorVT(EltTy, EC))) {
EC /= 2; EC = EC.divideCoefficientBy(2);
NumVectorRegs <<= 1; NumVectorRegs <<= 1;
} }
@ -1482,7 +1481,7 @@ unsigned TargetLoweringBase::getVectorTypeBreakdown(LLVMContext &Context, EVT VT
// end with a scalar if the target doesn't support vectors. // end with a scalar if the target doesn't support vectors.
while (EltCnt.getKnownMinValue() > 1 && while (EltCnt.getKnownMinValue() > 1 &&
!isTypeLegal(EVT::getVectorVT(Context, EltTy, EltCnt))) { !isTypeLegal(EVT::getVectorVT(Context, EltTy, EltCnt))) {
EltCnt /= 2; EltCnt = EltCnt.divideCoefficientBy(2);
NumVectorRegs <<= 1; NumVectorRegs <<= 1;
} }

View File

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

View File

@ -61,9 +61,10 @@ TEST(ScalableVectorMVTsTest, HelperFuncs) {
EXPECT_EQ(Vnx2i32.widenIntegerVectorElementType(Ctx), Vnx2i64); EXPECT_EQ(Vnx2i32.widenIntegerVectorElementType(Ctx), Vnx2i64);
EXPECT_EQ(Vnx4i32.getHalfNumVectorElementsVT(Ctx), Vnx2i32); 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::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 // Check that float->int conversion works
EVT Vnx2f64 = EVT::getVectorVT(Ctx, MVT::f64, ElementCount::getScalable(2)); 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->getNumElements(), 4U);
EXPECT_EQ(V4Int64Ty->getElementType()->getScalarSizeInBits(), 64U); EXPECT_EQ(V4Int64Ty->getElementType()->getScalarSizeInBits(), 64U);
auto *V2Int64Ty = auto *V2Int64Ty = dyn_cast<FixedVectorType>(
dyn_cast<FixedVectorType>(VectorType::get(Int64Ty, EltCnt / 2)); VectorType::get(Int64Ty, EltCnt.divideCoefficientBy(2)));
ASSERT_NE(nullptr, V2Int64Ty); ASSERT_NE(nullptr, V2Int64Ty);
EXPECT_EQ(V2Int64Ty->getNumElements(), 2U); EXPECT_EQ(V2Int64Ty->getNumElements(), 2U);
EXPECT_EQ(V2Int64Ty->getElementType()->getScalarSizeInBits(), 64U); EXPECT_EQ(V2Int64Ty->getElementType()->getScalarSizeInBits(), 64U);
@ -166,8 +166,8 @@ TEST(VectorTypesTest, Scalable) {
EXPECT_EQ(ScV4Int64Ty->getMinNumElements(), 4U); EXPECT_EQ(ScV4Int64Ty->getMinNumElements(), 4U);
EXPECT_EQ(ScV4Int64Ty->getElementType()->getScalarSizeInBits(), 64U); EXPECT_EQ(ScV4Int64Ty->getElementType()->getScalarSizeInBits(), 64U);
auto *ScV2Int64Ty = auto *ScV2Int64Ty = dyn_cast<ScalableVectorType>(
dyn_cast<ScalableVectorType>(VectorType::get(Int64Ty, EltCnt / 2)); VectorType::get(Int64Ty, EltCnt.divideCoefficientBy(2)));
ASSERT_NE(nullptr, ScV2Int64Ty); ASSERT_NE(nullptr, ScV2Int64Ty);
EXPECT_EQ(ScV2Int64Ty->getMinNumElements(), 2U); EXPECT_EQ(ScV2Int64Ty->getMinNumElements(), 2U);
EXPECT_EQ(ScV2Int64Ty->getElementType()->getScalarSizeInBits(), 64U); EXPECT_EQ(ScV2Int64Ty->getElementType()->getScalarSizeInBits(), 64U);