Index: include/llvm/CodeGen/BasicTTIImpl.h =================================================================== --- include/llvm/CodeGen/BasicTTIImpl.h +++ include/llvm/CodeGen/BasicTTIImpl.h @@ -758,7 +758,7 @@ unsigned Cost = LT.first; if (Src->isVectorTy() && - Src->getPrimitiveSizeInBits() < LT.second.getSizeInBits()) { + Src->getScalableSizeInBits().Unscaled < LT.second.getSizeInBits()) { // This is a vector load that legalizes to a larger type than the vector // itself. Unless the corresponding extending load or truncating store is // legal, then this will scalarize. Index: include/llvm/IR/DataLayout.h =================================================================== --- include/llvm/IR/DataLayout.h +++ include/llvm/IR/DataLayout.h @@ -381,6 +381,134 @@ return getPointerTypeSizeInBits(Ty) / 8; } + struct ScalableSize { + uint64_t Unscaled; + uint64_t Scaled; + + ScalableSize(uint64_t Unscaled, uint64_t Scaled) + : Unscaled(Unscaled), Scaled(Scaled) {} + + ScalableSize() {} + + bool operator==(const ScalableSize RHS) const { + return Unscaled == RHS.Unscaled && Scaled == RHS.Scaled; + } + + bool operator!=(const ScalableSize RHS) const { + return Unscaled != RHS.Unscaled || Scaled != RHS.Scaled; + } + + bool operator<(const ScalableSize& RHS) const { + // Fixed-length fast case + if (Scaled == RHS.Scaled) + return Unscaled < RHS.Unscaled; + + // Scalable fast case + if (Unscaled == RHS.Unscaled) + return Scaled < RHS.Scaled; + + // Runtime dependent, no matter the unscaled difference. + if (Scaled > RHS.Scaled) + return false; + + // We know Scaled < RHS.Scaled now. + if (Unscaled <= RHS.Unscaled) + return true; + + // {largeU, smallS} vs. {smallU, largeS} + // if the unscaled difference is less than the scaled difference, + // then this is true. Otherwise it's runtime dependent. + auto SDiff = RHS.Scaled - Scaled; + auto UDiff = Unscaled - RHS.Unscaled; + return UDiff < SDiff; + } + + bool operator<=(const ScalableSize& RHS) const { + // Fixed-length fast case + if (Scaled == RHS.Scaled) + return Unscaled <= RHS.Unscaled; + + // Scalable fast case + if (Unscaled == RHS.Unscaled) + return Scaled <= RHS.Scaled; + + // Runtime dependent, no matter the unscaled difference. + if (Scaled > RHS.Scaled) + return false; + + // We know Scaled < RHS.Scaled now. + if (Unscaled <= RHS.Unscaled) + return true; + + // {largeU, smallS} vs. {smallU, largeS} + // if the unscaled difference is less than or equal to the scaled + // difference, then this is true. Otherwise it's runtime dependent. + auto SDiff = RHS.Scaled - Scaled; + auto UDiff = Unscaled - RHS.Unscaled; + return UDiff <= SDiff; + } + + bool operator>(const ScalableSize& RHS) const { + // Fixed-length fast case + if (Scaled == RHS.Scaled) + return Unscaled > RHS.Unscaled; + + // Scalable fast case + if (Unscaled == RHS.Unscaled) + return Scaled > RHS.Scaled; + + // Runtime dependent, no matter the unscaled difference. + if (Scaled < RHS.Scaled) + return false; + + // We know Scaled > RHS.Scaled now. + if (Unscaled >= RHS.Unscaled) + return true; + + // {smallU, largeS} vs. {largeU, smallS} + // if the unscaled difference is less than the scaled difference, + // then this is true. Otherwise it's runtime dependent. + auto SDiff = Scaled - RHS.Scaled; + auto UDiff = RHS.Unscaled - Unscaled; + return UDiff < SDiff; + } + + bool operator>=(const ScalableSize& RHS) const { + // Fixed-length fast case + if (Scaled == RHS.Scaled) + return Unscaled >= RHS.Unscaled; + + // Scalable fast case + if (Unscaled == RHS.Unscaled) + return Scaled >= RHS.Scaled; + + // Runtime dependent, no matter the unscaled difference. + if (Scaled < RHS.Scaled) + return false; + + // We know Scaled > RHS.Scaled now. + if (Unscaled >= RHS.Unscaled) + return true; + + // {smallU, largeS} vs. {largeU, smallS} + // if the unscaled difference is less than or equal to the scaled + // difference, then this is true. Otherwise it's runtime dependent. + auto SDiff = Scaled - RHS.Scaled; + auto UDiff = RHS.Unscaled - Unscaled; + return UDiff <= SDiff; + } + + ScalableSize& operator+=(const ScalableSize& RHS) { + Unscaled += RHS.Unscaled; + Scaled += RHS.Scaled; + return *this; + } + + ScalableSize operator*(uint64_t Count) { + return ScalableSize(Unscaled * Count, Scaled * Count); + } + }; + /// Size examples: /// /// Type SizeInBits StoreSizeInBits AllocSizeInBits[*] @@ -404,6 +532,8 @@ /// have a size (Type::isSized() must return true). uint64_t getTypeSizeInBits(Type *Ty) const; + ScalableSize getScalableTypeSizeInBits(Type *Ty) const; + /// Returns the maximum number of bytes that may be overwritten by /// storing the specified type. /// @@ -412,6 +542,13 @@ return (getTypeSizeInBits(Ty) + 7) / 8; } + ScalableSize getScalableTypeStoreSize(Type *Ty) const { + // Is overloading bits/bytes wise? + auto Bits = getScalableTypeSizeInBits(Ty); + return ScalableSize((Bits.Unscaled+7)/8, + (Bits.Scaled+7)/8); + } + /// Returns the maximum number of bits that may be overwritten by /// storing the specified type; always a multiple of 8. /// @@ -430,6 +567,15 @@ return alignTo(getTypeStoreSize(Ty), getABITypeAlignment(Ty)); } + ScalableSize getScalableTypeAllocSize(Type *Ty) const { + auto Bytes = getScalableTypeStoreSize(Ty); + auto *VTy = dyn_cast(Ty); + if (!VTy || !VTy->isScalable()) + Bytes.Unscaled = alignTo(Bytes.Unscaled, getABITypeAlignment(Ty)); + + return Bytes; + } + /// Returns the offset in bits between successive objects of the /// specified type, including alignment padding; always a multiple of 8. /// @@ -439,6 +585,10 @@ return 8 * getTypeAllocSize(Ty); } + ScalableSize getScalableTypeAllocSizeInBits(Type *Ty) const { + return getScalableTypeAllocSize(Ty) * 8; + } + /// Returns the minimum ABI-required alignment for the specified type. unsigned getABITypeAlignment(Type *Ty) const; @@ -519,16 +669,23 @@ /// Used to lazily calculate structure layout information for a target machine, /// based on the DataLayout structure. class StructLayout { - uint64_t StructSize; + DataLayout::ScalableSize StructSize; unsigned StructAlignment; unsigned IsPadded : 1; unsigned NumElements : 31; - uint64_t MemberOffsets[1]; // variable sized array! + DataLayout::ScalableSize MemberOffsets[1]; // variable sized array! public: - uint64_t getSizeInBytes() const { return StructSize; } + uint64_t getSizeInBytes() const { return StructSize.Unscaled; } + + DataLayout::ScalableSize getScalableSizeInBytes() const { return StructSize; } - uint64_t getSizeInBits() const { return 8 * StructSize; } + uint64_t getSizeInBits() const { return 8 * StructSize.Unscaled; } + + DataLayout::ScalableSize getScalableSizeInBits() const { + return DataLayout::ScalableSize(StructSize.Unscaled * 8, + StructSize.Scaled * 8); + } unsigned getAlignment() const { return StructAlignment; } @@ -542,7 +699,7 @@ uint64_t getElementOffset(unsigned Idx) const { assert(Idx < NumElements && "Invalid element idx!"); - return MemberOffsets[Idx]; + return MemberOffsets[Idx].Unscaled; } uint64_t getElementOffsetInBits(unsigned Idx) const { @@ -597,6 +754,30 @@ } } +inline DataLayout::ScalableSize +DataLayout::getScalableTypeSizeInBits(Type *Ty) const { + switch(Ty->getTypeID()) { + default: + return {getTypeSizeInBits(Ty), 0ULL}; + case Type::ArrayTyID: { + ArrayType *ATy = cast(Ty); + return getScalableTypeAllocSizeInBits(ATy->getElementType()) * + ATy->getNumElements(); + } + case Type::StructTyID: + return getStructLayout(cast(Ty))->getScalableSizeInBits(); + case Type::VectorTyID: { + VectorType *VTy = cast(Ty); + auto EltCnt = VTy->getElementCount(); + uint64_t MinBits = EltCnt.Min * getTypeSizeInBits(VTy->getElementType()); + if (EltCnt.Scalable) + return {0ULL, MinBits}; + else + return {MinBits, 0ULL}; + } + } +} + } // end namespace llvm #endif // LLVM_IR_DATALAYOUT_H Index: include/llvm/IR/Type.h =================================================================== --- include/llvm/IR/Type.h +++ include/llvm/IR/Type.h @@ -294,6 +294,124 @@ /// type. unsigned getScalarSizeInBits() const LLVM_READONLY; + struct ScalableSize { + unsigned Unscaled; + unsigned Scaled; + + ScalableSize(unsigned Unscaled, unsigned Scaled) + : Unscaled(Unscaled), Scaled(Scaled) {} + + bool operator==(const ScalableSize& RHS) const { + return Unscaled == RHS.Unscaled && Scaled == RHS.Scaled; + } + + bool operator!=(const ScalableSize& RHS) const { + return Unscaled != RHS.Unscaled || Scaled != RHS.Scaled; + } + + bool operator<(const ScalableSize& RHS) const { + // Fixed-length fast case + if (Scaled == RHS.Scaled) + return Unscaled < RHS.Unscaled; + + // Scalable fast case + if (Unscaled == RHS.Unscaled) + return Scaled < RHS.Scaled; + + // Runtime dependent, no matter the unscaled difference. + if (Scaled > RHS.Scaled) + return false; + + // We know Scaled < RHS.Scaled now. + if (Unscaled <= RHS.Unscaled) + return true; + + // {largeU, smallS} vs. {smallU, largeS} + // if the unscaled difference is less than the scaled difference, + // then this is true. Otherwise it's runtime dependent. + auto SDiff = RHS.Scaled - Scaled; + auto UDiff = Unscaled - RHS.Unscaled; + return UDiff < SDiff; + } + + bool operator<=(const ScalableSize& RHS) const { + // Fixed-length fast case + if (Scaled == RHS.Scaled) + return Unscaled <= RHS.Unscaled; + + // Scalable fast case + if (Unscaled == RHS.Unscaled) + return Scaled <= RHS.Scaled; + + // Runtime dependent, no matter the unscaled difference. + if (Scaled > RHS.Scaled) + return false; + + // We know Scaled < RHS.Scaled now. + if (Unscaled <= RHS.Unscaled) + return true; + + // {largeU, smallS} vs. {smallU, largeS} + // if the unscaled difference is less than the scaled difference, + // then this is true. Otherwise it's runtime dependent. + auto SDiff = RHS.Scaled - Scaled; + auto UDiff = Unscaled - RHS.Unscaled; + return UDiff <= SDiff; + } + + bool operator>(const ScalableSize& RHS) const { + // Fixed-length fast case + if (Scaled == RHS.Scaled) + return Unscaled > RHS.Unscaled; + + // Scalable fast case + if (Unscaled == RHS.Unscaled) + return Scaled > RHS.Scaled; + + // Runtime dependent, no matter the unscaled difference. + if (Scaled < RHS.Scaled) + return false; + + // We know Scaled > RHS.Scaled now. + if (Unscaled >= RHS.Unscaled) + return true; + + // {smallU, largeS} vs. {largeU, smallS} + // if the unscaled difference is less than the scaled difference, + // then this is true. Otherwise it's runtime dependent. + auto SDiff = Scaled - RHS.Scaled; + auto UDiff = RHS.Unscaled - Unscaled; + return UDiff < SDiff; + } + + bool operator>=(const ScalableSize& RHS) const { + // Fixed-length fast case + if (Scaled == RHS.Scaled) + return Unscaled >= RHS.Unscaled; + + // Scalable fast case + if (Unscaled == RHS.Unscaled) + return Scaled >= RHS.Scaled; + + // Runtime dependent, no matter the unscaled difference. + if (Scaled < RHS.Scaled) + return false; + + // We know Scaled > RHS.Scaled now. + if (Unscaled >= RHS.Unscaled) + return true; + + // {smallU, largeS} vs. {largeU, smallS} + // if the unscaled difference is less than or equal to the scaled + // difference, then this is true. Otherwise it's runtime dependent. + auto SDiff = Scaled - RHS.Scaled; + auto UDiff = RHS.Unscaled - Unscaled; + return UDiff <= SDiff; + } + }; + + ScalableSize getScalableSizeInBits() const LLVM_READONLY; + /// Return the width of the mantissa of this type. This is only valid on /// floating-point types. If the FP type does not have a stable mantissa (e.g. /// ppc long double), this method returns -1. Index: lib/Analysis/ConstantFolding.cpp =================================================================== --- lib/Analysis/ConstantFolding.cpp +++ lib/Analysis/ConstantFolding.cpp @@ -624,7 +624,7 @@ StringRef Str; if (getConstantStringInfo(CE, Str) && !Str.empty()) { size_t StrLen = Str.size(); - unsigned NumBits = Ty->getPrimitiveSizeInBits(); + unsigned NumBits = Ty->getScalableSizeInBits().Unscaled; // Replace load with immediate integer if the result is an integer or fp // value. if ((NumBits >> 3) == StrLen + 1 && (NumBits & 7) == 0 && Index: lib/Analysis/InstructionSimplify.cpp =================================================================== --- lib/Analysis/InstructionSimplify.cpp +++ lib/Analysis/InstructionSimplify.cpp @@ -3266,7 +3266,7 @@ // Turn icmp (ptrtoint x), (ptrtoint/constant) into a compare of the input // if the integer type is the same size as the pointer type. if (MaxRecurse && isa(LI) && - Q.DL.getTypeSizeInBits(SrcTy) == DstTy->getPrimitiveSizeInBits()) { + Q.DL.getTypeSizeInBits(SrcTy) == DstTy->getScalableSizeInBits().Unscaled) { if (Constant *RHSC = dyn_cast(RHS)) { // Transfer the cast to the constant. if (Value *V = SimplifyICmpInst(Pred, SrcOp, Index: lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- lib/CodeGen/CodeGenPrepare.cpp +++ lib/CodeGen/CodeGenPrepare.cpp @@ -1560,7 +1560,7 @@ // Only handle legal scalar cases. Anything else requires too much work. Type *Ty = CountZeros->getType(); - unsigned SizeInBits = Ty->getPrimitiveSizeInBits(); + unsigned SizeInBits = Ty->getScalableSizeInBits().Unscaled; if (Ty->isVectorTy() || SizeInBits > DL->getLargestLegalIntTypeSizeInBits()) return false; Index: lib/IR/AutoUpgrade.cpp =================================================================== --- lib/IR/AutoUpgrade.cpp +++ lib/IR/AutoUpgrade.cpp @@ -454,7 +454,7 @@ auto Idx = F->getFunctionType()->getParamType(2); if (Idx->isFPOrFPVectorTy()) { rename(F); - unsigned IdxSize = Idx->getPrimitiveSizeInBits(); + unsigned IdxSize = Idx->getScalableSizeInBits().Unscaled; unsigned EltSize = Idx->getScalarSizeInBits(); Intrinsic::ID Permil2ID; if (EltSize == 64 && IdxSize == 128) @@ -1158,7 +1158,7 @@ CallInst &CI, Value *&Rep) { Name = Name.substr(12); // Remove avx512.mask. - unsigned VecWidth = CI.getType()->getPrimitiveSizeInBits(); + unsigned VecWidth = CI.getType()->getScalableSizeInBits().Unscaled; unsigned EltWidth = CI.getType()->getScalarSizeInBits(); Intrinsic::ID IID; if (Name.startswith("max.p")) { @@ -1640,7 +1640,7 @@ Type *ExtTy = Type::getInt32Ty(C); if (CI->getOperand(0)->getType()->isIntegerTy(8)) ExtTy = Type::getInt64Ty(C); - unsigned NumElts = CI->getType()->getPrimitiveSizeInBits() / + unsigned NumElts = CI->getType()->getScalableSizeInBits().Unscaled / ExtTy->getPrimitiveSizeInBits(); Rep = Builder.CreateZExt(CI->getArgOperand(0), ExtTy); Rep = Builder.CreateVectorSplat(NumElts, Rep); @@ -1784,7 +1784,7 @@ Rep = upgradeMaskedCompare(Builder, *CI, CmpEq ? 0 : 6, true); } else if (IsX86 && Name.startswith("avx512.mask.fpclass.p")) { Type *OpTy = CI->getArgOperand(0)->getType(); - unsigned VecWidth = OpTy->getPrimitiveSizeInBits(); + unsigned VecWidth = OpTy->getScalableSizeInBits().Unscaled; unsigned EltWidth = OpTy->getScalarSizeInBits(); Intrinsic::ID IID; if (VecWidth == 128 && EltWidth == 32) @@ -1807,7 +1807,7 @@ Rep = ApplyX86MaskOn1BitsVec(Builder, Rep, CI->getArgOperand(2)); } else if (IsX86 && Name.startswith("avx512.mask.cmp.p")) { Type *OpTy = CI->getArgOperand(0)->getType(); - unsigned VecWidth = OpTy->getPrimitiveSizeInBits(); + unsigned VecWidth = OpTy->getScalableSizeInBits().Unscaled; unsigned EltWidth = OpTy->getScalarSizeInBits(); Intrinsic::ID IID; if (VecWidth == 128 && EltWidth == 32) @@ -2100,7 +2100,7 @@ Name.startswith("avx512.mask.shuf.f"))) { unsigned Imm = cast(CI->getArgOperand(2))->getZExtValue(); Type *VT = CI->getType(); - unsigned NumLanes = VT->getPrimitiveSizeInBits() / 128; + unsigned NumLanes = VT->getScalableSizeInBits().Unscaled / 128; unsigned NumElementsInLane = 128 / VT->getScalarSizeInBits(); unsigned ControlBitsMask = NumLanes - 1; unsigned NumControlBits = NumLanes / 2; @@ -3103,7 +3103,7 @@ } else if (IsX86 && (Name.startswith("avx512.mask.pternlog.") || Name.startswith("avx512.maskz.pternlog."))) { bool ZeroMask = Name[11] == 'z'; - unsigned VecWidth = CI->getType()->getPrimitiveSizeInBits(); + unsigned VecWidth = CI->getType()->getScalableSizeInBits().Unscaled; unsigned EltWidth = CI->getType()->getScalarSizeInBits(); Intrinsic::ID IID; if (VecWidth == 128 && EltWidth == 32) @@ -3132,7 +3132,7 @@ Name.startswith("avx512.maskz.vpmadd52"))) { bool ZeroMask = Name[11] == 'z'; bool High = Name[20] == 'h' || Name[21] == 'h'; - unsigned VecWidth = CI->getType()->getPrimitiveSizeInBits(); + unsigned VecWidth = CI->getType()->getScalableSizeInBits().Unscaled; Intrinsic::ID IID; if (VecWidth == 128 && !High) IID = Intrinsic::x86_avx512_vpmadd52l_uq_128; @@ -3161,7 +3161,7 @@ Name.startswith("avx512.maskz.vpermt2var."))) { bool ZeroMask = Name[11] == 'z'; bool IndexForm = Name[17] == 'i'; - unsigned VecWidth = CI->getType()->getPrimitiveSizeInBits(); + unsigned VecWidth = CI->getType()->getScalableSizeInBits().Unscaled; unsigned EltWidth = CI->getType()->getScalarSizeInBits(); bool IsFloat = CI->getType()->isFPOrFPVectorTy(); Intrinsic::ID IID; @@ -3223,7 +3223,7 @@ Name.startswith("avx512.maskz.vpdpbusds."))) { bool ZeroMask = Name[11] == 'z'; bool IsSaturating = Name[ZeroMask ? 21 : 20] == 's'; - unsigned VecWidth = CI->getType()->getPrimitiveSizeInBits(); + unsigned VecWidth = CI->getType()->getScalableSizeInBits().Unscaled; Intrinsic::ID IID; if (VecWidth == 128 && !IsSaturating) IID = Intrinsic::x86_avx512_vpdpbusd_128; @@ -3253,7 +3253,7 @@ Name.startswith("avx512.maskz.vpdpwssds."))) { bool ZeroMask = Name[11] == 'z'; bool IsSaturating = Name[ZeroMask ? 21 : 20] == 's'; - unsigned VecWidth = CI->getType()->getPrimitiveSizeInBits(); + unsigned VecWidth = CI->getType()->getScalableSizeInBits().Unscaled; Intrinsic::ID IID; if (VecWidth == 128 && !IsSaturating) IID = Intrinsic::x86_avx512_vpdpwssd_128; Index: lib/IR/DataLayout.cpp =================================================================== --- lib/IR/DataLayout.cpp +++ lib/IR/DataLayout.cpp @@ -46,26 +46,39 @@ StructLayout::StructLayout(StructType *ST, const DataLayout &DL) { assert(!ST->isOpaque() && "Cannot get layout of opaque structs"); StructAlignment = 0; - StructSize = 0; + StructSize = {0, 0}; IsPadded = false; NumElements = ST->getNumElements(); // Loop over each of the elements, placing them in memory. for (unsigned i = 0, e = NumElements; i != e; ++i) { Type *Ty = ST->getElementType(i); + VectorType *VTy = dyn_cast(Ty); + bool IsScalable = VTy && VTy->isScalable(); + + // TODO: Figure out what to do for alignment with scalable vectors. If + // the scaled bytes are a multiple of the required alignment we're fine, + // but if they aren't I don't think we have a way of generating a + // simple address at compile time -- we would need to align at runtime. + // For now, just insist that all structs containing scalable vectors are + // packed. + assert((!IsScalable || ST->isPacked()) && + "Unable to determine alignment of unpacked scalable struct"); unsigned TyAlign = ST->isPacked() ? 1 : DL.getABITypeAlignment(Ty); // Add padding if necessary to align the data element properly. - if ((StructSize & (TyAlign-1)) != 0) { + if ((StructSize.Unscaled & (TyAlign-1)) != 0) { IsPadded = true; - StructSize = alignTo(StructSize, TyAlign); + StructSize = {alignTo(StructSize.Unscaled, TyAlign), 0}; } // Keep track of maximum alignment constraint. StructAlignment = std::max(TyAlign, StructAlignment); MemberOffsets[i] = StructSize; - StructSize += DL.getTypeAllocSize(Ty); // Consume space for this data item + + // Consume space for this data item + StructSize += DL.getScalableTypeAllocSize(Ty); } // Empty structures have alignment of 1 byte. @@ -73,22 +86,23 @@ // Add padding to the end of the struct so that it could be put in an array // and all array elements would be aligned correctly. - if ((StructSize & (StructAlignment-1)) != 0) { + if ((StructSize.Unscaled & (StructAlignment-1)) != 0) { IsPadded = true; - StructSize = alignTo(StructSize, StructAlignment); + StructSize = {alignTo(StructSize.Unscaled, StructAlignment), 0}; } } /// getElementContainingOffset - Given a valid offset into the structure, /// return the structure index that contains it. unsigned StructLayout::getElementContainingOffset(uint64_t Offset) const { - const uint64_t *SI = - std::upper_bound(&MemberOffsets[0], &MemberOffsets[NumElements], Offset); + const DataLayout::ScalableSize SOffset(Offset, 0ULL); + const DataLayout::ScalableSize *SI = + std::upper_bound(&MemberOffsets[0], &MemberOffsets[NumElements], SOffset); assert(SI != &MemberOffsets[0] && "Offset not in structure type!"); --SI; - assert(*SI <= Offset && "upper_bound didn't work"); - assert((SI == &MemberOffsets[0] || *(SI-1) <= Offset) && - (SI+1 == &MemberOffsets[NumElements] || *(SI+1) > Offset) && + assert(*SI <= SOffset && "upper_bound didn't work"); + assert((SI == &MemberOffsets[0] || *(SI-1) <= SOffset) && + (SI+1 == &MemberOffsets[NumElements] || *(SI+1) > SOffset) && "Upper bound didn't work!"); // Multiple fields can have the same offset if any of them are zero sized. @@ -597,7 +611,8 @@ // malloc it, then use placement new. int NumElts = Ty->getNumElements(); StructLayout *L = (StructLayout *) - safe_malloc(sizeof(StructLayout)+(NumElts-1) * sizeof(uint64_t)); + safe_malloc(sizeof(StructLayout) + + (NumElts-1) * sizeof(DataLayout::ScalableSize)); // Set SL before calling StructLayout's ctor. The ctor could cause other // entries to be added to TheMap, invalidating our reference. Index: lib/IR/Instructions.cpp =================================================================== --- lib/IR/Instructions.cpp +++ lib/IR/Instructions.cpp @@ -2755,8 +2755,8 @@ } // Get the bit sizes, we'll need these - unsigned SrcBits = SrcTy->getPrimitiveSizeInBits(); // 0 for ptr - unsigned DestBits = DestTy->getPrimitiveSizeInBits(); // 0 for ptr + auto SrcBits = SrcTy->getScalableSizeInBits(); // 0 for ptr + auto DestBits = DestTy->getScalableSizeInBits(); // 0 for ptr // Run through the possibilities ... if (DestTy->isIntegerTy()) { // Casting to integral @@ -2817,12 +2817,12 @@ } } - unsigned SrcBits = SrcTy->getPrimitiveSizeInBits(); // 0 for ptr - unsigned DestBits = DestTy->getPrimitiveSizeInBits(); // 0 for ptr + auto SrcBits = SrcTy->getScalableSizeInBits(); // 0 for ptr + auto DestBits = DestTy->getScalableSizeInBits(); // 0 for ptr // Could still have vectors of pointers if the number of elements doesn't // match - if (SrcBits == 0 || DestBits == 0) + if (SrcBits.Unscaled == 0 || DestBits.Unscaled == 0) return false; if (SrcBits != DestBits) @@ -3032,7 +3032,8 @@ // For non-pointer cases, the cast is okay if the source and destination bit // widths are identical. if (!SrcPtrTy) - return SrcTy->getPrimitiveSizeInBits() == DstTy->getPrimitiveSizeInBits(); + return SrcTy->getScalableSizeInBits() == + DstTy->getScalableSizeInBits(); // If both are pointers then the address spaces must match. if (SrcPtrTy->getAddressSpace() != DstPtrTy->getAddressSpace()) Index: lib/IR/Type.cpp =================================================================== --- lib/IR/Type.cpp +++ lib/IR/Type.cpp @@ -122,7 +122,7 @@ case Type::PPC_FP128TyID: return 128; case Type::X86_MMXTyID: return 64; case Type::IntegerTyID: return cast(this)->getBitWidth(); - case Type::VectorTyID: return cast(this)->getBitWidth(); + case Type::VectorTyID: return 0; // TODO: Just an assert for scalable vectors? default: return 0; } } @@ -131,6 +131,24 @@ return getScalarType()->getPrimitiveSizeInBits(); } +Type::ScalableSize Type::getScalableSizeInBits() const { + auto ID = getTypeID(); + if (ID == Type::HalfTyID || ID == Type::FloatTyID || ID == Type::DoubleTyID || + ID == Type::X86_FP80TyID || ID == Type::FP128TyID || + ID == Type::PPC_FP128TyID || ID == Type::X86_MMXTyID || + ID == Type::IntegerTyID) + return { getPrimitiveSizeInBits(), 0 }; + + if (auto *VTy = dyn_cast(this)) { + if (VTy->isScalable()) + return { 0, VTy->getBitWidth() }; + else + return { VTy->getBitWidth(), 0 }; + } + + return {0, 0}; +} + int Type::getFPMantissaWidth() const { if (auto *VTy = dyn_cast(this)) return VTy->getElementType()->getFPMantissaWidth(); Index: lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp =================================================================== --- lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp +++ lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp @@ -848,7 +848,7 @@ // dispatch registers are function args. unsigned WaveDispatchNumSGPR = 0, WaveDispatchNumVGPR = 0; for (auto &Arg : MF.getFunction().args()) { - unsigned NumRegs = (Arg.getType()->getPrimitiveSizeInBits() + 31) / 32; + unsigned NumRegs = (Arg.getType()->getScalableSizeInBits().Unscaled + 31) / 32; if (Arg.hasAttribute(Attribute::InReg)) WaveDispatchNumSGPR += NumRegs; else Index: lib/Target/PowerPC/PPCTargetTransformInfo.cpp =================================================================== --- lib/Target/PowerPC/PPCTargetTransformInfo.cpp +++ lib/Target/PowerPC/PPCTargetTransformInfo.cpp @@ -420,7 +420,7 @@ // 32b/64b to VSR correctly and cheaply. But BaseT::getMemoryOpCost and // PPCTargetLowering can't compute the cost appropriately. So here we // explicitly check this case. - unsigned MemBytes = Src->getPrimitiveSizeInBits(); + unsigned MemBytes = Src->getScalableSizeInBits().Unscaled; if (Opcode == Instruction::Load && ST->hasVSX() && IsAltivecType && (MemBytes == 64 || (ST->hasP8Vector() && MemBytes == 32))) return 1; Index: lib/Target/SystemZ/SystemZTargetTransformInfo.cpp =================================================================== --- lib/Target/SystemZ/SystemZTargetTransformInfo.cpp +++ lib/Target/SystemZ/SystemZTargetTransformInfo.cpp @@ -34,7 +34,7 @@ int SystemZTTIImpl::getIntImmCost(const APInt &Imm, Type *Ty) { assert(Ty->isIntegerTy()); - unsigned BitSize = Ty->getPrimitiveSizeInBits(); + unsigned BitSize = Ty->getScalableSizeInBits().Unscaled; // There is no cost model for constants with a bit size of 0. Return TCC_Free // here, so that constant hoisting will ignore this constant. if (BitSize == 0) @@ -67,7 +67,7 @@ const APInt &Imm, Type *Ty) { assert(Ty->isIntegerTy()); - unsigned BitSize = Ty->getPrimitiveSizeInBits(); + unsigned BitSize = Ty->getScalableSizeInBits().Unscaled; // There is no cost model for constants with a bit size of 0. Return TCC_Free // here, so that constant hoisting will ignore this constant. if (BitSize == 0) @@ -185,7 +185,7 @@ const APInt &Imm, Type *Ty) { assert(Ty->isIntegerTy()); - unsigned BitSize = Ty->getPrimitiveSizeInBits(); + unsigned BitSize = Ty->getScalableSizeInBits().Unscaled; // There is no cost model for constants with a bit size of 0. Return TCC_Free // here, so that constant hoisting will ignore this constant. if (BitSize == 0) @@ -543,7 +543,7 @@ unsigned SystemZTTIImpl:: getVectorTruncCost(Type *SrcTy, Type *DstTy) { assert (SrcTy->isVectorTy() && DstTy->isVectorTy()); - assert (SrcTy->getPrimitiveSizeInBits() > DstTy->getPrimitiveSizeInBits() && + assert (SrcTy->getScalableSizeInBits() > DstTy->getScalableSizeInBits() && "Packing must reduce size of vector type."); assert (SrcTy->getVectorNumElements() == DstTy->getVectorNumElements() && "Packing should not change number of elements."); Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -5708,7 +5708,8 @@ // Extract constant bits from constant pool vector. if (auto *Cst = getTargetConstantFromNode(Op)) { Type *CstTy = Cst->getType(); - if (!CstTy->isVectorTy() || (SizeInBits != CstTy->getPrimitiveSizeInBits())) + if (!CstTy->isVectorTy() || + (CstTy->getScalableSizeInBits().Unscaled != SizeInBits)) return false; unsigned SrcEltSizeInBits = CstTy->getScalarSizeInBits(); @@ -26809,7 +26810,7 @@ return false; // XOP has v16i8/v8i16/v4i32/v2i64 variable vector shifts. - if (Subtarget.hasXOP() && Ty->getPrimitiveSizeInBits() == 128 && + if (Subtarget.hasXOP() && Ty->getScalableSizeInBits().Unscaled == 128 && (Bits == 8 || Bits == 16 || Bits == 32 || Bits == 64)) return false; Index: lib/Target/X86/X86ShuffleDecodeConstantPool.cpp =================================================================== --- lib/Target/X86/X86ShuffleDecodeConstantPool.cpp +++ lib/Target/X86/X86ShuffleDecodeConstantPool.cpp @@ -43,7 +43,7 @@ if (!CstEltTy->isIntegerTy()) return false; - unsigned CstSizeInBits = CstTy->getPrimitiveSizeInBits(); + unsigned CstSizeInBits = CstTy->getScalableSizeInBits().Unscaled; unsigned CstEltSizeInBits = CstTy->getScalarSizeInBits(); unsigned NumCstElts = CstTy->getVectorNumElements(); @@ -114,7 +114,7 @@ void DecodePSHUFBMask(const Constant *C, SmallVectorImpl &ShuffleMask) { Type *MaskTy = C->getType(); - unsigned MaskTySize = MaskTy->getPrimitiveSizeInBits(); + unsigned MaskTySize = MaskTy->getScalableSizeInBits().Unscaled; (void)MaskTySize; assert((MaskTySize == 128 || MaskTySize == 256 || MaskTySize == 512) && "Unexpected vector size."); @@ -154,7 +154,7 @@ void DecodeVPERMILPMask(const Constant *C, unsigned ElSize, SmallVectorImpl &ShuffleMask) { Type *MaskTy = C->getType(); - unsigned MaskTySize = MaskTy->getPrimitiveSizeInBits(); + unsigned MaskTySize = MaskTy->getScalableSizeInBits().Unscaled; (void)MaskTySize; assert((MaskTySize == 128 || MaskTySize == 256 || MaskTySize == 512) && "Unexpected vector size."); @@ -191,7 +191,7 @@ void DecodeVPERMIL2PMask(const Constant *C, unsigned M2Z, unsigned ElSize, SmallVectorImpl &ShuffleMask) { Type *MaskTy = C->getType(); - unsigned MaskTySize = MaskTy->getPrimitiveSizeInBits(); + unsigned MaskTySize = MaskTy->getScalableSizeInBits().Unscaled; (void)MaskTySize; assert((MaskTySize == 128 || MaskTySize == 256) && "Unexpected vector size."); @@ -243,7 +243,7 @@ } void DecodeVPPERMMask(const Constant *C, SmallVectorImpl &ShuffleMask) { - assert(C->getType()->getPrimitiveSizeInBits() == 128 && + assert(C->getType()->getScalableSizeInBits().Unscaled == 128 && "Unexpected vector size."); // The shuffle mask requires a byte vector. @@ -294,7 +294,7 @@ void DecodeVPERMVMask(const Constant *C, unsigned ElSize, SmallVectorImpl &ShuffleMask) { Type *MaskTy = C->getType(); - unsigned MaskTySize = MaskTy->getPrimitiveSizeInBits(); + unsigned MaskTySize = MaskTy->getScalableSizeInBits().Unscaled; (void)MaskTySize; assert((MaskTySize == 128 || MaskTySize == 256 || MaskTySize == 512) && "Unexpected vector size."); @@ -322,7 +322,7 @@ void DecodeVPERMV3Mask(const Constant *C, unsigned ElSize, SmallVectorImpl &ShuffleMask) { Type *MaskTy = C->getType(); - unsigned MaskTySize = MaskTy->getPrimitiveSizeInBits(); + unsigned MaskTySize = MaskTy->getScalableSizeInBits().Unscaled; (void)MaskTySize; assert((MaskTySize == 128 || MaskTySize == 256 || MaskTySize == 512) && "Unexpected vector size."); Index: lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCalls.cpp +++ lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -387,7 +387,7 @@ // SSE2/AVX2 uses all the first 64-bits of the 128-bit vector // operand to compute the shift amount. auto VT = cast(CDV->getType()); - unsigned BitWidth = VT->getElementType()->getPrimitiveSizeInBits(); + unsigned BitWidth = VT->getElementType()->getScalableSizeInBits().Unscaled; assert((64 % BitWidth) == 0 && "Unexpected packed shift size"); unsigned NumSubElts = 64 / BitWidth; @@ -406,7 +406,7 @@ auto VT = cast(Vec->getType()); auto SVT = VT->getElementType(); unsigned VWidth = VT->getNumElements(); - unsigned BitWidth = SVT->getPrimitiveSizeInBits(); + unsigned BitWidth = SVT->getScalableSizeInBits().Unscaled; // If shift-by-zero then just return the original value. if (Count.isNullValue()) @@ -572,7 +572,7 @@ return UndefValue::get(ResTy); Type *ArgTy = Arg0->getType(); - unsigned NumLanes = ResTy->getPrimitiveSizeInBits() / 128; + unsigned NumLanes = ResTy->getScalableSizeInBits().Unscaled / 128; unsigned NumDstElts = ResTy->getVectorNumElements(); unsigned NumSrcElts = ArgTy->getVectorNumElements(); assert(NumDstElts == (2 * NumSrcElts) && "Unexpected packing types"); @@ -2679,7 +2679,7 @@ // SSE2/AVX2 uses only the first 64-bits of the 128-bit vector // operand to compute the shift amount. Value *Arg1 = II->getArgOperand(1); - assert(Arg1->getType()->getPrimitiveSizeInBits() == 128 && + assert(Arg1->getType()->getScalableSizeInBits().Unscaled == 128 && "Unexpected packed shift size"); unsigned VWidth = Arg1->getType()->getVectorNumElements(); @@ -2792,8 +2792,8 @@ Value *Op1 = II->getArgOperand(1); unsigned VWidth0 = Op0->getType()->getVectorNumElements(); unsigned VWidth1 = Op1->getType()->getVectorNumElements(); - assert(Op0->getType()->getPrimitiveSizeInBits() == 128 && - Op1->getType()->getPrimitiveSizeInBits() == 128 && VWidth0 == 2 && + assert(Op0->getType()->getScalableSizeInBits().Unscaled == 128 && + Op1->getType()->getScalableSizeInBits().Unscaled == 128 && VWidth0 == 2 && VWidth1 == 16 && "Unexpected operand sizes"); // See if we're dealing with constant values. @@ -2830,8 +2830,8 @@ // bits of the lower 64-bits. The upper 64-bits are undefined. Value *Op0 = II->getArgOperand(0); unsigned VWidth = Op0->getType()->getVectorNumElements(); - assert(Op0->getType()->getPrimitiveSizeInBits() == 128 && VWidth == 2 && - "Unexpected operand size"); + assert(Op0->getType()->getScalableSizeInBits().Unscaled == 128 && + VWidth == 2 && "Unexpected operand size"); // See if we're dealing with constant values. ConstantInt *CILength = dyn_cast(II->getArgOperand(1)); @@ -2854,9 +2854,9 @@ Value *Op0 = II->getArgOperand(0); Value *Op1 = II->getArgOperand(1); unsigned VWidth = Op0->getType()->getVectorNumElements(); - assert(Op0->getType()->getPrimitiveSizeInBits() == 128 && - Op1->getType()->getPrimitiveSizeInBits() == 128 && VWidth == 2 && - Op1->getType()->getVectorNumElements() == 2 && + assert(Op0->getType()->getScalableSizeInBits().Unscaled == 128 && + Op1->getType()->getScalableSizeInBits().Unscaled == 128 && + VWidth == 2 && Op1->getType()->getVectorNumElements() == 2 && "Unexpected operand size"); // See if we're dealing with constant values. @@ -2891,9 +2891,9 @@ Value *Op1 = II->getArgOperand(1); unsigned VWidth0 = Op0->getType()->getVectorNumElements(); unsigned VWidth1 = Op1->getType()->getVectorNumElements(); - assert(Op0->getType()->getPrimitiveSizeInBits() == 128 && - Op1->getType()->getPrimitiveSizeInBits() == 128 && VWidth0 == 2 && - VWidth1 == 2 && "Unexpected operand sizes"); + assert(Op0->getType()->getScalableSizeInBits().Unscaled == 128 && + Op1->getType()->getScalableSizeInBits().Unscaled == 128 && + VWidth0 == 2 && VWidth1 == 2 && "Unexpected operand sizes"); // See if we're dealing with constant values. ConstantInt *CILength = dyn_cast(II->getArgOperand(2)); @@ -2953,8 +2953,8 @@ if (match(Mask, m_SExt(m_Value(BoolVec))) && BoolVec->getType()->isVectorTy() && BoolVec->getType()->getScalarSizeInBits() == 1) { - assert(Mask->getType()->getPrimitiveSizeInBits() == - II->getType()->getPrimitiveSizeInBits() && + assert(Mask->getType()->getScalableSizeInBits() == + II->getType()->getScalableSizeInBits()&& "Not expecting mask and operands with different sizes"); unsigned NumMaskElts = Mask->getType()->getVectorNumElements(); Index: lib/Transforms/InstCombine/InstCombineCasts.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCasts.cpp +++ lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -469,7 +469,7 @@ return nullptr; VectorType *VecType = cast(VecInput->getType()); - unsigned VecWidth = VecType->getPrimitiveSizeInBits(); + unsigned VecWidth = VecType->getScalableSizeInBits().Unscaled; unsigned DestWidth = DestType->getPrimitiveSizeInBits(); unsigned ShiftAmount = ShiftVal ? ShiftVal->getZExtValue() : 0; Index: lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp +++ lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp @@ -1510,7 +1510,7 @@ unsigned InnerVWidth = Ty0->getVectorNumElements(); assert(VWidth == (InnerVWidth * 2) && "Unexpected input size"); - unsigned NumLanes = Ty0->getPrimitiveSizeInBits() / 128; + unsigned NumLanes = Ty0->getScalableSizeInBits().Unscaled / 128; unsigned VWidthPerLane = VWidth / NumLanes; unsigned InnerVWidthPerLane = InnerVWidth / NumLanes; Index: unittests/IR/VectorTypesTest.cpp =================================================================== --- unittests/IR/VectorTypesTest.cpp +++ unittests/IR/VectorTypesTest.cpp @@ -7,8 +7,10 @@ // //===----------------------------------------------------------------------===// +#include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Type.h" #include "gtest/gtest.h" using namespace llvm; @@ -72,7 +74,6 @@ VectorType *ScV4Float64Ty = VectorType::get(Float64Ty, EltCnt); ASSERT_TRUE(ScV4Float64Ty->isScalable()); - EXPECT_EQ(VectorType::getExtendedElementVectorType(ScV8Int16Ty), ScV8Int32Ty); EXPECT_EQ(VectorType::getTruncatedElementVectorType(ScV8Int32Ty), ScV8Int16Ty); @@ -87,4 +88,263 @@ ASSERT_TRUE(EltCnt.Scalable); } +TEST(VectorTypesTest, FixedLenComparisons) { + LLVMContext Ctx; + + Type *Int32Ty = Type::getInt32Ty(Ctx); + Type *Int64Ty = Type::getInt64Ty(Ctx); + + VectorType *V2Int32Ty = VectorType::get(Int32Ty, 2); + VectorType *V4Int32Ty = VectorType::get(Int32Ty, 4); + + VectorType *V2Int64Ty = VectorType::get(Int64Ty, 2); + + Type::ScalableSize V2I32Len = V2Int32Ty->getScalableSizeInBits(); + EXPECT_EQ(V2I32Len.Unscaled, 64U); + EXPECT_EQ(V2I32Len.Scaled, 0U); + + EXPECT_LT(V2Int32Ty->getScalableSizeInBits(), + V4Int32Ty->getScalableSizeInBits()); + EXPECT_GT(V2Int64Ty->getScalableSizeInBits(), + V2Int32Ty->getScalableSizeInBits()); + EXPECT_EQ(V4Int32Ty->getScalableSizeInBits(), + V2Int64Ty->getScalableSizeInBits()); + EXPECT_NE(V2Int32Ty->getScalableSizeInBits(), + V2Int64Ty->getScalableSizeInBits()); + + DataLayout DL(""); + SmallVector Fields({V2Int32Ty, V4Int32Ty}); + auto *StructTy = StructType::get(Ctx, Fields, /*isPacked=*/true); + auto SLen = DL.getScalableTypeSizeInBits(StructTy); + EXPECT_EQ(SLen.Unscaled, 192ULL); + EXPECT_EQ(SLen.Scaled, 0ULL); + + auto *ArrayTy = ArrayType::get(V4Int32Ty, 8); + auto ALen = DL.getScalableTypeSizeInBits(ArrayTy); + EXPECT_EQ(ALen.Unscaled, 1024ULL); + EXPECT_EQ(ALen.Scaled, 0ULL); +} + +TEST(VectorTypesTest, ScalableComparisons) { + LLVMContext Ctx; + + Type *Int32Ty = Type::getInt32Ty(Ctx); + Type *Int64Ty = Type::getInt64Ty(Ctx); + + VectorType *ScV2Int32Ty = VectorType::get(Int32Ty, {2, true}); + VectorType *ScV4Int32Ty = VectorType::get(Int32Ty, {4, true}); + + VectorType *ScV2Int64Ty = VectorType::get(Int64Ty, {2, true}); + + Type::ScalableSize ScV2I32Len = ScV2Int32Ty->getScalableSizeInBits(); + EXPECT_EQ(ScV2I32Len.Unscaled, 0U); + EXPECT_EQ(ScV2I32Len.Scaled, 64U); + + EXPECT_LT(ScV2Int32Ty->getScalableSizeInBits(), + ScV4Int32Ty->getScalableSizeInBits()); + EXPECT_GT(ScV2Int64Ty->getScalableSizeInBits(), + ScV2Int32Ty->getScalableSizeInBits()); + EXPECT_EQ(ScV4Int32Ty->getScalableSizeInBits(), + ScV2Int64Ty->getScalableSizeInBits()); + EXPECT_NE(ScV2Int32Ty->getScalableSizeInBits(), + ScV2Int64Ty->getScalableSizeInBits()); + + DataLayout DL(""); + SmallVector Fields({ScV2Int32Ty, ScV4Int32Ty}); + auto *StructTy = StructType::get(Ctx, Fields, /*isPacked=*/true); + auto SLen = DL.getScalableTypeSizeInBits(StructTy); + EXPECT_EQ(SLen.Unscaled, 0ULL); + EXPECT_EQ(SLen.Scaled, 192ULL); + + auto *ArrayTy = ArrayType::get(ScV4Int32Ty, 8); + auto ALen = DL.getScalableTypeSizeInBits(ArrayTy); + EXPECT_EQ(ALen.Unscaled, 0ULL); + EXPECT_EQ(ALen.Scaled, 1024ULL); +} + +TEST(VectorTypesTest, MixedComparisons) { + LLVMContext Ctx; + DataLayout DL(""); + + Type *Int32Ty = Type::getInt32Ty(Ctx); + Type *Int64Ty = Type::getInt64Ty(Ctx); + + VectorType *V2I32Ty = VectorType::get(Int32Ty, {2, false}); + VectorType *V2I64Ty = VectorType::get(Int64Ty, {2, false}); + VectorType *ScV2I32Ty = VectorType::get(Int32Ty, {2, true}); + VectorType *ScV2I64Ty = VectorType::get(Int64Ty, {2, true}); + + // Compare a fixed-size-only object vs. scalable-size-only object with + // same base size + // False: {X, 0} == {0, X} + EXPECT_FALSE(V2I64Ty->getScalableSizeInBits() == + ScV2I64Ty->getScalableSizeInBits()); + // True: {X, 0} != {0, X} + EXPECT_TRUE(V2I64Ty->getScalableSizeInBits() != + ScV2I64Ty->getScalableSizeInBits()); + // False: {X, 0} < {0, X} + EXPECT_FALSE(V2I64Ty->getScalableSizeInBits() < + ScV2I64Ty->getScalableSizeInBits()); + // True: {X, 0} <= {0, X} + EXPECT_TRUE(V2I64Ty->getScalableSizeInBits() <= + ScV2I64Ty->getScalableSizeInBits()); + // False: {X, 0} > {0, X} + EXPECT_FALSE(V2I64Ty->getScalableSizeInBits() > + ScV2I64Ty->getScalableSizeInBits()); + // False: {X, 0} >= {0, X} + EXPECT_FALSE(V2I64Ty->getScalableSizeInBits() >= + ScV2I64Ty->getScalableSizeInBits()); + // True: {0, X} >= {X, 0} + EXPECT_TRUE(ScV2I64Ty->getScalableSizeInBits() >= + V2I64Ty->getScalableSizeInBits()); + + // Compare a fixed-size-only object vs. scalable-size-only object with + // the scalable object having a larger base size + // False: {X, 0} == {0, Y} where X < Y + EXPECT_FALSE(V2I32Ty->getScalableSizeInBits() == + ScV2I64Ty->getScalableSizeInBits()); + // True: {X, 0} != {0, Y} where X < Y + EXPECT_TRUE(V2I32Ty->getScalableSizeInBits() != + ScV2I64Ty->getScalableSizeInBits()); + // True: {X, 0} < {0, Y} where X < Y + EXPECT_TRUE(V2I32Ty->getScalableSizeInBits() < + ScV2I64Ty->getScalableSizeInBits()); + // True: {X, 0} <= {0, Y} where X < Y + EXPECT_TRUE(V2I32Ty->getScalableSizeInBits() <= + ScV2I64Ty->getScalableSizeInBits()); + // False: {0, Y} < {X, 0} where X < Y + EXPECT_FALSE(ScV2I64Ty->getScalableSizeInBits() <= + V2I32Ty->getScalableSizeInBits()); + // False: {X, 0} > {0, Y} where X < Y + EXPECT_FALSE(V2I32Ty->getScalableSizeInBits() > + ScV2I64Ty->getScalableSizeInBits()); + // True: {0, Y} > {X, 0} where X < Y + EXPECT_TRUE(ScV2I64Ty->getScalableSizeInBits() > + V2I32Ty->getScalableSizeInBits()); + // False: {X, 0} >= {0, Y} where X < Y + EXPECT_FALSE(V2I32Ty->getScalableSizeInBits() >= + ScV2I64Ty->getScalableSizeInBits()); + // True: {0, Y} >= {X, 0} where X < Y + EXPECT_TRUE(ScV2I64Ty->getScalableSizeInBits() >= + V2I32Ty->getScalableSizeInBits()); + + // Compare a fixed-size-only object vs. a scalable-size-only object with + // the scalable object having a smaller base size + // False: {X, 0} == {0, Y} where X > Y + EXPECT_FALSE(V2I64Ty->getScalableSizeInBits() == + ScV2I32Ty->getScalableSizeInBits()); + // True: {X, 0} != {0, Y} where X > Y + EXPECT_TRUE(V2I64Ty->getScalableSizeInBits() != + ScV2I32Ty->getScalableSizeInBits()); + // False: {X, 0} < {0, Y} where X > Y + EXPECT_FALSE(V2I64Ty->getScalableSizeInBits() < + ScV2I32Ty->getScalableSizeInBits()); + // False: {0, Y} < {X, 0} where X > Y + EXPECT_FALSE(ScV2I32Ty->getScalableSizeInBits() < + V2I64Ty->getScalableSizeInBits()); + // False: {X, 0} <= {0, Y} where X > Y + EXPECT_FALSE(V2I64Ty->getScalableSizeInBits() <= + ScV2I32Ty->getScalableSizeInBits()); + // False: {0, Y} <= {X, 0} where X > Y + EXPECT_FALSE(ScV2I32Ty->getScalableSizeInBits() <= + V2I64Ty->getScalableSizeInBits()); + // False: {X, 0} > {0, Y} where X > Y + EXPECT_FALSE(V2I64Ty->getScalableSizeInBits() > + ScV2I32Ty->getScalableSizeInBits()); + // False: {0, Y} > {X, 0} where X > Y + EXPECT_FALSE(ScV2I32Ty->getScalableSizeInBits() > + V2I64Ty->getScalableSizeInBits()); + // False: {X, 0} >= {0, Y} where X > Y + EXPECT_FALSE(V2I64Ty->getScalableSizeInBits() >= + ScV2I32Ty->getScalableSizeInBits()); + // False: {0, Y} >= {X, 0} where X > Y + EXPECT_FALSE(ScV2I32Ty->getScalableSizeInBits() >= + V2I64Ty->getScalableSizeInBits()); + + SmallVector Fields({V2I32Ty, ScV2I64Ty}); + auto *U64S128Ty = StructType::get(Ctx, Fields, /*isPacked=*/true); + auto SLen = DL.getScalableTypeSizeInBits(U64S128Ty); + EXPECT_EQ(SLen.Unscaled, 64ULL); + EXPECT_EQ(SLen.Scaled, 128ULL); + + Fields = {V2I64Ty, ScV2I64Ty}; + auto U128S128Ty = StructType::get(Ctx, Fields, /*isPacked=*/true); + + // False: {X, Y} == {Z, Y} where X < Z + EXPECT_FALSE(DL.getScalableTypeSizeInBits(U64S128Ty) == + DL.getScalableTypeSizeInBits(U128S128Ty)); + // True: {X, Y} != {Z, Y} where X < Z + EXPECT_TRUE(DL.getScalableTypeSizeInBits(U64S128Ty) != + DL.getScalableTypeSizeInBits(U128S128Ty)); + // True: {X, Y} < {Z, Y} where X < Z + EXPECT_TRUE(DL.getScalableTypeSizeInBits(U64S128Ty) < + DL.getScalableTypeSizeInBits(U128S128Ty)); + // True: {X, Y} <= {Z, Y} where X < Z + EXPECT_TRUE(DL.getScalableTypeSizeInBits(U64S128Ty) <= + DL.getScalableTypeSizeInBits(U128S128Ty)); + // False: {Z, Y} <= {X, Y} where X < Z + EXPECT_FALSE(DL.getScalableTypeSizeInBits(U128S128Ty) <= + DL.getScalableTypeSizeInBits(U64S128Ty)); + // False: {X, Y} > {Z, Y} where X < Z + EXPECT_FALSE(DL.getScalableTypeSizeInBits(U64S128Ty) > + DL.getScalableTypeSizeInBits(U128S128Ty)); + // False: {X, Y} >= {Z, Y} where X < Z + EXPECT_FALSE(DL.getScalableTypeSizeInBits(U64S128Ty) >= + DL.getScalableTypeSizeInBits(U128S128Ty)); + // True: {Z, Y} >= {X, Y} where X < Z + EXPECT_TRUE(DL.getScalableTypeSizeInBits(U128S128Ty) >= + DL.getScalableTypeSizeInBits(U64S128Ty)); + + Fields = {V2I64Ty, ScV2I32Ty}; + auto U128S64Ty = StructType::get(Ctx, Fields, /*isPacked=*/true); + + // False: {X, Y} == {X, Z} where Y > Z + EXPECT_FALSE(DL.getScalableTypeSizeInBits(U128S128Ty) == + DL.getScalableTypeSizeInBits(U128S64Ty)); + // True: {X, Y} != {X, Z} where Y > Z + EXPECT_TRUE(DL.getScalableTypeSizeInBits(U128S128Ty) != + DL.getScalableTypeSizeInBits(U128S64Ty)); + // False: {X, Y} < {X, Z} where Y > Z + EXPECT_FALSE(DL.getScalableTypeSizeInBits(U128S128Ty) < + DL.getScalableTypeSizeInBits(U128S64Ty)); + // False {X, Y} <= {X, Z} where Y > Z + EXPECT_FALSE(DL.getScalableTypeSizeInBits(U128S128Ty) <= + DL.getScalableTypeSizeInBits(U128S64Ty)); + // True {X, Z} <= {X, Y} where Y > Z + EXPECT_TRUE(DL.getScalableTypeSizeInBits(U128S64Ty) <= + DL.getScalableTypeSizeInBits(U128S128Ty)); + // True: {X, Y} > {X, Z} where Y > Z + EXPECT_TRUE(DL.getScalableTypeSizeInBits(U128S128Ty) > + DL.getScalableTypeSizeInBits(U128S64Ty)); + // False: {X, Z} > {X, Y} where Y > Z + EXPECT_FALSE(DL.getScalableTypeSizeInBits(U128S64Ty) > + DL.getScalableTypeSizeInBits(U128S128Ty)); + // True: {X, Y} >= {X, Z} where Y > Z + EXPECT_TRUE(DL.getScalableTypeSizeInBits(U128S128Ty) >= + DL.getScalableTypeSizeInBits(U128S64Ty)); + + + + + // False: {W, X} == {Y, Z} where W == Z && X == Y + EXPECT_FALSE(DL.getScalableTypeSizeInBits(U64S128Ty) == + DL.getScalableTypeSizeInBits(U128S64Ty)); + // True: {W, X} != {Y, Z} where W == Z && X == Y + EXPECT_TRUE(DL.getScalableTypeSizeInBits(U64S128Ty) != + DL.getScalableTypeSizeInBits(U128S64Ty)); + // False: {W, X} < {Y, Z} where W == Z && X == Y + EXPECT_FALSE(DL.getScalableTypeSizeInBits(U64S128Ty) < + DL.getScalableTypeSizeInBits(U128S64Ty)); + // False: {W, X} <= {Y, Z} where W == Z && X == Y + EXPECT_FALSE(DL.getScalableTypeSizeInBits(U64S128Ty) <= + DL.getScalableTypeSizeInBits(U128S64Ty)); + + + + auto *ArrayTy = ArrayType::get(U128S64Ty, 3); + auto ALen = DL.getScalableTypeSizeInBits(ArrayTy); + EXPECT_EQ(ALen.Unscaled, 384ULL); + EXPECT_EQ(ALen.Scaled, 192ULL); +} + }