Index: clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- clang/lib/CodeGen/CGBuiltin.cpp +++ clang/lib/CodeGen/CGBuiltin.cpp @@ -5650,7 +5650,7 @@ if (BuiltinID == NEON::BI__builtin_neon_splatq_lane_v) NumElements = NumElements * 2; if (BuiltinID == NEON::BI__builtin_neon_splat_laneq_v) - NumElements = NumElements / 2; + NumElements = NumElements.halve(); Ops[0] = Builder.CreateBitCast(Ops[0], VTy); return EmitNeonSplat(Ops[0], cast(Ops[1]), NumElements); @@ -8483,8 +8483,7 @@ case SVE::BI__builtin_sve_svtbl2_f64: { SVETypeFlags TF(Builtin->TypeModifier); auto VTy = cast(getSVEType(TF)); - auto TupleTy = llvm::VectorType::get(VTy->getElementType(), - VTy->getElementCount() * 2); + auto TupleTy = llvm::VectorType::getDoubleElementsVectorType(VTy); Function *FExtr = CGM.getIntrinsic(Intrinsic::aarch64_sve_tuple_get, {VTy, TupleTy}); Value *V0 = Builder.CreateCall(FExtr, {Ops[0], Builder.getInt32(0)}); Index: llvm/include/llvm/CodeGen/ValueTypes.h =================================================================== --- llvm/include/llvm/CodeGen/ValueTypes.h +++ llvm/include/llvm/CodeGen/ValueTypes.h @@ -414,7 +414,16 @@ 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.halve()); + } + + // 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. Index: llvm/include/llvm/IR/DerivedTypes.h =================================================================== --- llvm/include/llvm/IR/DerivedTypes.h +++ llvm/include/llvm/IR/DerivedTypes.h @@ -504,7 +504,7 @@ 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.halve()); } /// This static method returns a VectorType with twice as many elements as the Index: llvm/include/llvm/Support/MachineValueType.h =================================================================== --- llvm/include/llvm/Support/MachineValueType.h +++ llvm/include/llvm/Support/MachineValueType.h @@ -425,7 +425,7 @@ MVT EltVT = getVectorElementType(); auto EltCnt = getVectorElementCount(); assert(EltCnt.isKnownEven() && "Splitting vector, but not in half!"); - return getVectorVT(EltVT, EltCnt / 2); + return getVectorVT(EltVT, EltCnt.halve()); } /// Returns true if the given vector is a power of 2. Index: llvm/include/llvm/Support/TypeSize.h =================================================================== --- llvm/include/llvm/Support/TypeSize.h +++ llvm/include/llvm/Support/TypeSize.h @@ -44,10 +44,6 @@ 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,32 @@ return *this; } - ElementCount &operator/=(unsigned RHS) { - Min /= RHS; - return *this; + /// This function returns an ElementCount with exactly half the number of + /// elements and will assert if not a known multiple of 2. + ElementCount halve() const { + assert(isKnownMultipleOf(2) && + "Halving an ElementCount that is not a multiple of 2"); + return ElementCount(Min / 2, Scalable); + } + + /// 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 coefficientDiv(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 +247,16 @@ 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 coefficientDiv(uint64_t RHS) const { + return {MinSize / RHS, IsScalable}; } TypeSize &operator-=(TypeSize RHS) { @@ -258,18 +279,6 @@ 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 +310,10 @@ // 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 +370,6 @@ 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); } Index: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -19515,8 +19515,9 @@ } 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().coefficientDiv(DestSrcRatio); EVT ScalarVT = SrcVT.getScalarType(); if ((ExtIdx % DestSrcRatio) == 0) { SDLoc DL(N); @@ -20683,7 +20684,8 @@ } 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.coefficientDiv(Scale)); NewIdx = DAG.getVectorIdxConstant(InsIdx / Scale, DL); } } Index: llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -2635,8 +2635,8 @@ EVT HalfElementVT = IsFloat ? EVT::getFloatingPointVT(InElementSize/2) : EVT::getIntegerVT(*DAG.getContext(), InElementSize/2); - EVT HalfVT = EVT::getVectorVT(*DAG.getContext(), HalfElementVT, - NumElements/2); + EVT HalfVT = + EVT::getVectorVT(*DAG.getContext(), HalfElementVT, NumElements.halve()); SDValue HalfLo; SDValue HalfHi; @@ -5062,11 +5062,12 @@ 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 WidenOps(NumOps); unsigned j = 0; for (; j != End-Idx; ++j) @@ -5087,7 +5088,8 @@ 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 WidenOps(NumOps); SDValue UndefVal = DAG.getUNDEF(LdTy); { Index: llvm/lib/CodeGen/TargetLoweringBase.cpp =================================================================== --- llvm/lib/CodeGen/TargetLoweringBase.cpp +++ llvm/lib/CodeGen/TargetLoweringBase.cpp @@ -831,9 +831,7 @@ "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 @@ // <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 @@ } // Vectors with illegal element types are expanded. - EVT NVT = EVT::getVectorVT(Context, EltVT, VT.getVectorElementCount() / 2); + EVT NVT = + EVT::getVectorVT(Context, EltVT, VT.getVectorElementCount().halve()); return LegalizeKind(TypeSplitVector, NVT); } @@ -982,7 +981,7 @@ // scalar. while (EC.getKnownMinValue() > 1 && !TLI->isTypeLegal(MVT::getVectorVT(EltTy, EC))) { - EC /= 2; + EC = EC.halve(); NumVectorRegs <<= 1; } @@ -1482,7 +1481,7 @@ // 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.halve(); NumVectorRegs <<= 1; } Index: llvm/lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -10569,7 +10569,7 @@ "invalid tuple vector type!"); EVT SplitVT = EVT::getVectorVT(*DAG.getContext(), VT.getVectorElementType(), - VT.getVectorElementCount() / N); + VT.getVectorElementCount().coefficientDiv(N)); assert(isTypeLegal(SplitVT)); SmallVector VTs(N, SplitVT); @@ -14363,9 +14363,7 @@ 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)); Index: llvm/unittests/CodeGen/ScalableVectorMVTsTest.cpp =================================================================== --- llvm/unittests/CodeGen/ScalableVectorMVTsTest.cpp +++ llvm/unittests/CodeGen/ScalableVectorMVTsTest.cpp @@ -61,9 +61,10 @@ 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.coefficientDiv(2)), + MVT::nxv1i64); // Check that float->int conversion works EVT Vnx2f64 = EVT::getVectorVT(Ctx, MVT::f64, ElementCount::getScalable(2)); Index: llvm/unittests/IR/VectorTypesTest.cpp =================================================================== --- llvm/unittests/IR/VectorTypesTest.cpp +++ llvm/unittests/IR/VectorTypesTest.cpp @@ -72,7 +72,7 @@ EXPECT_EQ(V4Int64Ty->getElementType()->getScalarSizeInBits(), 64U); auto *V2Int64Ty = - dyn_cast(VectorType::get(Int64Ty, EltCnt / 2)); + dyn_cast(VectorType::get(Int64Ty, EltCnt.halve())); ASSERT_NE(nullptr, V2Int64Ty); EXPECT_EQ(V2Int64Ty->getNumElements(), 2U); EXPECT_EQ(V2Int64Ty->getElementType()->getScalarSizeInBits(), 64U); @@ -167,7 +167,7 @@ EXPECT_EQ(ScV4Int64Ty->getElementType()->getScalarSizeInBits(), 64U); auto *ScV2Int64Ty = - dyn_cast(VectorType::get(Int64Ty, EltCnt / 2)); + dyn_cast(VectorType::get(Int64Ty, EltCnt.halve())); ASSERT_NE(nullptr, ScV2Int64Ty); EXPECT_EQ(ScV2Int64Ty->getMinNumElements(), 2U); EXPECT_EQ(ScV2Int64Ty->getElementType()->getScalarSizeInBits(), 64U);