diff --git a/llvm/include/llvm/Support/TypeSize.h b/llvm/include/llvm/Support/TypeSize.h --- a/llvm/include/llvm/Support/TypeSize.h +++ b/llvm/include/llvm/Support/TypeSize.h @@ -37,8 +37,10 @@ return { Min * RHS, Scalable }; } ElementCount operator/(unsigned RHS) { + assert(Min % RHS == 0 && "Min is not a multiple of RHS."); return { Min / RHS, Scalable }; } + ElementCount operator>>=(unsigned RHS) { return {Min >> RHS, Scalable}; } bool operator==(const ElementCount& RHS) const { return Min == RHS.Min && Scalable == RHS.Scalable; @@ -46,6 +48,14 @@ bool operator!=(const ElementCount& RHS) const { return !(*this == RHS); } + /// Checks whether Min is a power of 2. Note that for a ElementCount + /// instance where Scalable is set to true, this is not generally + /// true from a mathematical point of view, as the Scalable property + /// in this case is saying that the ElementCount is holding a value + /// that is and unknown multiple of MinSize. For example, + /// ElementCount(4, true).isPowerOf2() == true, but its symbolic + /// value is 4 x UNKNOWN. + bool isPowerOf2() { return isPowerOf2_32(Min); } }; // This class is used to represent the size of types. If the type is of fixed @@ -121,6 +131,12 @@ return { MinSize / RHS, IsScalable }; } + friend TypeSize operator/(const TypeSize &LHS, const TypeSize &RHS) { + assert(LHS.IsScalable == RHS.IsScalable && + "Division of scalable and fixed types"); + + return {LHS.MinSize / RHS.MinSize, RHS.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). @@ -152,6 +168,22 @@ // Returns true if the type size is zero. bool isZero() const { return MinSize == 0; } + /// Checks whether MinSize is a power of 2. Note that for a TypeSize + /// instance where IsScalable is set to true, this is not generally + /// true from a mathematical point of view, as the IsScalable + /// property in this case is saying that the TypeSize is holding a + /// value that is and unknown multiple of MinSize. For example, + /// TypeSize(4, true).isPowerOf2() == true, but its symbolic value + /// is 4 x UNKNOWN. + bool isPowerOf2() const { return isPowerOf2_32(MinSize); } + + /// Returns a TypeSize where MinSize is set to be the smallest power + /// of 2 greater than the MinSize of the current instance. The + /// IsScalable fiels is preserved. + static TypeSize getNextPowerOf2(TypeSize &TS) { + return {NextPowerOf2(TS.MinSize), TS.IsScalable}; + } + // Casts to a uint64_t if this is a fixed-width size. // // This interface is deprecated and will be removed in a future version diff --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp --- a/llvm/lib/CodeGen/TargetLoweringBase.cpp +++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp @@ -944,37 +944,47 @@ MVT &RegisterVT, TargetLoweringBase *TLI) { // Figure out the right, legal destination reg to copy into. - unsigned NumElts = VT.getVectorNumElements(); + ElementCount EC = VT.getVectorElementCount(); MVT EltTy = VT.getVectorElementType(); unsigned NumVectorRegs = 1; - // FIXME: We don't support non-power-of-2-sized vectors for now. Ideally we - // could break down into LHS/RHS like LegalizeDAG does. - if (!isPowerOf2_32(NumElts)) { - NumVectorRegs = NumElts; - NumElts = 1; + // FIXME: We don't support non-power-of-2-sized vectors for now. + // Ideally we could break down into LHS/RHS like LegalizeDAG does. + if (!EC.isPowerOf2()) { + // Split EC to unit size (scalable property is preserved). + NumVectorRegs = EC.Min; + EC = EC / NumVectorRegs; } - // Divide the input until we get to a supported size. This will always - // end with a scalar if the target doesn't support vectors. - while (NumElts > 1 && !TLI->isTypeLegal(MVT::getVectorVT(EltTy, NumElts))) { - NumElts >>= 1; + // Divide the input until we get to a supported size. For example, + // on a target where MVT::nxv4i32 is a legal type, MVT::nxv32i32 is + // split in 8 vectors of type MVT::nxv4i32. On a target where + // MVT::v4i16 is a legal type, MVT::v64i16 is split in 16 vectors of + // type MVT::v4i16. This loop will always end up with an EC that + // represent a scalar or a scalable scalar. For scalable EC, to the + // best of our knowledge, we do not expect to ever get to EC = {1, + // true} for any of the LLVM Targets. The assertion following the + // loop capture such situation. + while (EC.Min > 1 && !TLI->isTypeLegal(MVT::getVectorVT(EltTy, EC))) { + EC >>= 1; NumVectorRegs <<= 1; } + assert(!(EC.Scalable && EC.Min == 1) && "The split has resulted in a" + "scalable vector with one lane."); NumIntermediates = NumVectorRegs; - MVT NewVT = MVT::getVectorVT(EltTy, NumElts); + MVT NewVT = MVT::getVectorVT(EltTy, EC); if (!TLI->isTypeLegal(NewVT)) NewVT = EltTy; IntermediateVT = NewVT; - unsigned NewVTSize = NewVT.getSizeInBits(); + TypeSize NewVTSize = NewVT.getSizeInBits(); // Convert sizes such as i33 to i64. - if (!isPowerOf2_32(NewVTSize)) - NewVTSize = NextPowerOf2(NewVTSize); + if (!NewVTSize.isPowerOf2()) + NewVTSize = TypeSize::getNextPowerOf2(NewVTSize); MVT DestVT = TLI->getRegisterType(NewVT); RegisterVT = DestVT;