Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -2470,29 +2470,34 @@ elements. Vector types are used when multiple primitive data are operated in parallel using a single instruction (SIMD). A vector type requires a size (number of elements) and an underlying primitive data -type. Vector types are considered :ref:`first class `. +type. A vector type has an optional scalable property to represent a +vector of unknown length. Vector types are considered :ref:`first class `. :Syntax: :: - < <# elements> x > + < <# elements> x > ; vector + < n x <# elements> x > ; scalable vector The number of elements is a constant integer value larger than 0; elementtype may be any integer, floating point or pointer type. Vectors -of size zero are not allowed. +of size zero are not allowed. For scalable vectors the real number of +elements is an unknown integer multiple of #elements. :Examples: -+-------------------+--------------------------------------------------+ -| ``<4 x i32>`` | Vector of 4 32-bit integer values. | -+-------------------+--------------------------------------------------+ -| ``<8 x float>`` | Vector of 8 32-bit floating-point values. | -+-------------------+--------------------------------------------------+ -| ``<2 x i64>`` | Vector of 2 64-bit integer values. | -+-------------------+--------------------------------------------------+ -| ``<4 x i64*>`` | Vector of 4 pointers to 64-bit integer values. | -+-------------------+--------------------------------------------------+ ++-------------------+----------------------------------------------------+ +| ``<4 x i32>`` | Vector of 4 32-bit integer values. | ++-------------------+----------------------------------------------------+ +| ``<8 x float>`` | Vector of 8 32-bit floating-point values. | ++-------------------+----------------------------------------------------+ +| ``<2 x i64>`` | Vector of 2 64-bit integer values. | ++-------------------+----------------------------------------------------+ +| ``<4 x i64*>`` | Vector of 4 pointers to 64-bit integer values. | ++-------------------+----------------------------------------------------+ +| ```` | Vector with a multiple of 4 32-bit integer values. | ++-------------------+----------------------------------------------------+ .. _t_label: @@ -6713,7 +6718,8 @@ :: - = extractelement > , ; yields + = extractelement > , ; yields + = extractelement > , ; yields Overview: """"""""" @@ -6753,7 +6759,8 @@ :: - = insertelement > , , ; yields > + = insertelement > , , ; yields > + = insertelement > , , ; yields > Overview: """"""""" @@ -6795,7 +6802,8 @@ :: - = shufflevector > , > , ; yields > + = shufflevector > , > , ; yields > + = shufflevector > , > , ; yields > Overview: """"""""" Index: include/llvm/IR/DerivedTypes.h =================================================================== --- include/llvm/IR/DerivedTypes.h +++ include/llvm/IR/DerivedTypes.h @@ -364,15 +364,62 @@ /// Class to represent vector types. class VectorType : public SequentialType { - unsigned NumElements; +public: + /// A VectorType is of the form . M is the minimum number of + /// elements of type Ty contained within the vector, with the actual element + /// count being N * M. However, for all targets N is either statically unknown + /// or guaranteed to be one. For the latter case the extra complication is + /// discarded leading to: + /// + /// <4 x i32> - a vector of four i32s + /// - a vector with an unknown integer multiple of four i32s + class ElementCount { + private: + unsigned Min; // Minimum number of vector elements. + bool Scalable; // NumElements != MinNumElements + + public: + ElementCount(unsigned MinElts, bool IsScalable) + : Min(MinElts), Scalable(IsScalable) {} + + ElementCount operator*(unsigned RHS) { + return { Min * RHS, Scalable }; + } + ElementCount operator/(unsigned RHS) { + return { Min / RHS, Scalable }; + } + + bool operator==(const ElementCount& RHS) { + return Min == RHS.Min && Scalable == RHS.Scalable; + } + + unsigned getMinNumElements() const { + return Min; + } + + unsigned getNumElements() const { + assert(!Scalable && "NumElements is unknown for scalable vector!"); + return Min; + } + + bool isScalable() const { + return Scalable; + } + }; + +private: + ElementCount EC; VectorType(const VectorType &) = delete; const VectorType &operator=(const VectorType &) = delete; - VectorType(Type *ElType, unsigned NumEl); + VectorType(Type *ElType, ElementCount EC); public: /// This static method is the primary way to construct an VectorType. - static VectorType *get(Type *ElementType, unsigned NumElements); + static VectorType *get(Type *ElType, ElementCount EC); + static VectorType *get(Type *ElType, unsigned NumEls, bool Scalable=false) { + return VectorType::get(ElType, { NumEls, Scalable }); + } /// This static method gets a VectorType with the same number of elements as /// the input type, and the element type is an integer type of the same width @@ -381,7 +428,7 @@ unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits(); assert(EltBits && "Element size must be of a non-zero size"); Type *EltTy = IntegerType::get(VTy->getContext(), EltBits); - return VectorType::get(EltTy, VTy->getNumElements()); + return VectorType::get(EltTy, VTy->getElementCount()); } /// This static method is like getInteger except that the element types are @@ -389,7 +436,7 @@ static VectorType *getExtendedElementVectorType(VectorType *VTy) { unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits(); Type *EltTy = IntegerType::get(VTy->getContext(), EltBits * 2); - return VectorType::get(EltTy, VTy->getNumElements()); + return VectorType::get(EltTy, VTy->getElementCount()); } /// This static method is like getInteger except that the element types are @@ -399,14 +446,14 @@ assert((EltBits & 1) == 0 && "Cannot truncate vector element with odd bit-width"); Type *EltTy = IntegerType::get(VTy->getContext(), EltBits / 2); - return VectorType::get(EltTy, VTy->getNumElements()); + return VectorType::get(EltTy, VTy->getElementCount()); } /// This static method returns a VectorType with half as many elements as the /// input type and the same element type. static VectorType *getHalfElementsVectorType(VectorType *VTy) { - unsigned NumElts = VTy->getNumElements(); - assert ((NumElts & 1) == 0 && + auto NumElts = VTy->getElementCount(); + assert ((NumElts.getMinNumElements() & 1) == 0 && "Cannot halve vector with odd number of elements."); return VectorType::get(VTy->getElementType(), NumElts/2); } @@ -414,7 +461,7 @@ /// This static method returns a VectorType with twice as many elements as the /// input type and the same element type. static VectorType *getDoubleElementsVectorType(VectorType *VTy) { - unsigned NumElts = VTy->getNumElements(); + auto NumElts = VTy->getElementCount(); return VectorType::get(VTy->getElementType(), NumElts*2); } @@ -422,12 +469,19 @@ static bool isValidElementType(Type *ElemTy); /// Return the number of elements in the Vector type. - unsigned getNumElements() const { return NumElements; } + ElementCount getElementCount() const { return EC; } - /// Return the number of bits in the Vector type. + /// Return the minimum number of elements in the Vector type to maintain + /// compatibility with existing code during the transition to ElementCount. + unsigned getNumElements() const { return EC.getMinNumElements(); } + + /// Return true when the number of elements is only known at runtime. + bool isScalable() const { return EC.isScalable(); } + + /// Return the minimum number of bits in the Vector type. /// Returns zero when the vector is a vector of pointers. unsigned getBitWidth() const { - return NumElements * getElementType()->getPrimitiveSizeInBits(); + return EC.getMinNumElements() * getElementType()->getPrimitiveSizeInBits(); } /// Methods for support type inquiry through isa, cast, and dyn_cast. @@ -440,6 +494,10 @@ return cast(this)->getNumElements(); } +unsigned Type::getVectorIsScalable() const { + return cast(this)->isScalable(); +} + /// Class to represent pointers. class PointerType : public SequentialType { PointerType(const PointerType &) = delete; Index: include/llvm/IR/Type.h =================================================================== --- include/llvm/IR/Type.h +++ include/llvm/IR/Type.h @@ -349,6 +349,7 @@ return ContainedTys[0]; } + inline unsigned getVectorIsScalable() const; inline unsigned getVectorNumElements() const; Type *getVectorElementType() const { assert(getTypeID() == VectorTyID); Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -681,6 +681,7 @@ KEYWORD(xchg); KEYWORD(nand); KEYWORD(max); KEYWORD(min); KEYWORD(umax); KEYWORD(umin); + KEYWORD(n); KEYWORD(x); KEYWORD(blockaddress); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -2417,7 +2417,19 @@ /// Type /// ::= '[' APSINTVAL 'x' Types ']' /// ::= '<' APSINTVAL 'x' Types '>' +/// ::= '<' 'n' 'x' APSINTVAL 'x' Types '>' bool LLParser::ParseArrayVectorType(Type *&Result, bool isVector) { + bool Scalable = false; /* assume fixed length vectors */ + + if (isVector && Lex.getKind() == lltok::kw_n) { + Lex.Lex(); // consume the 'n' + + if (ParseToken(lltok::kw_x, "expected 'x' after scalable vector specifier")) + return true; + + Scalable = true; /* scalable vector */ + } + if (Lex.getKind() != lltok::APSInt || Lex.getAPSIntVal().isSigned() || Lex.getAPSIntVal().getBitWidth() > 64) return TokError("expected number in address space"); @@ -2427,7 +2439,7 @@ Lex.Lex(); if (ParseToken(lltok::kw_x, "expected 'x' after element count")) - return true; + return true; LocTy TypeLoc = Lex.getLoc(); Type *EltTy = nullptr; @@ -2444,7 +2456,7 @@ return Error(SizeLoc, "size too large for vector"); if (!VectorType::isValidElementType(EltTy)) return Error(TypeLoc, "invalid vector element type"); - Result = VectorType::get(EltTy, unsigned(Size)); + Result = VectorType::get(EltTy, unsigned(Size), Scalable); } else { if (!ArrayType::isValidElementType(EltTy)) return Error(TypeLoc, "invalid array element type"); Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -37,6 +37,7 @@ exclaim, // ! bar, // | + kw_n, kw_x, kw_true, kw_false, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -2121,17 +2121,20 @@ return error("Invalid type"); ResultTy = ArrayType::get(ResultTy, Record[0]); break; - case bitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty] - if (Record.size() < 2) + case bitc::TYPE_CODE_VECTOR: { // VECTOR: [scalable, numelts, eltty] + unsigned Size = Record.size(); + if (Size < 2) return error("Invalid record"); - if (Record[0] == 0) + if (Record[Size - 2] == 0) return error("Invalid vector length"); - ResultTy = getTypeByID(Record[1]); + ResultTy = getTypeByID(Record[Size - 1]); if (!ResultTy || !StructType::isValidElementType(ResultTy)) return error("Invalid type"); - ResultTy = VectorType::get(ResultTy, Record[0]); + bool Scalable = Size > 2 ? Record[Size - 3] : false; + ResultTy = VectorType::get(ResultTy, Record[Size - 2], Scalable); break; } + } if (NumRecords >= TypeList.size()) return error("Invalid TYPE table"); Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -938,8 +938,9 @@ } case Type::VectorTyID: { VectorType *VT = cast(T); - // VECTOR [numelts, eltty] + // VECTOR [scalable, numelts, eltty] Code = bitc::TYPE_CODE_VECTOR; + TypeVals.push_back(VT->isScalable()); TypeVals.push_back(VT->getNumElements()); TypeVals.push_back(VE.getTypeID(VT->getElementType())); break; Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -536,7 +536,10 @@ } case Type::VectorTyID: { VectorType *PTy = cast(Ty); - OS << "<" << PTy->getNumElements() << " x "; + OS << '<'; + if (PTy->isScalable()) + OS << "n x "; + OS << PTy->getNumElements() << " x "; print(PTy->getElementType(), OS); OS << '>'; return; Index: lib/IR/Type.cpp =================================================================== --- lib/IR/Type.cpp +++ lib/IR/Type.cpp @@ -627,23 +627,24 @@ // VectorType Implementation //===----------------------------------------------------------------------===// -VectorType::VectorType(Type *ElType, unsigned NumEl) - : SequentialType(VectorTyID, ElType) { - NumElements = NumEl; +VectorType::VectorType(Type *ElType, ElementCount ElCount) + : SequentialType(VectorTyID, ElType), EC(ElCount) { } -VectorType *VectorType::get(Type *ElementType, unsigned NumElements) { - assert(NumElements > 0 && "#Elements of a VectorType must be greater than 0"); +VectorType *VectorType::get(Type *ElementType, ElementCount EC) { + assert(EC.getMinNumElements() > 0 && + "Minimum #Elements of a VectorType must be greater than 0."); assert(isValidElementType(ElementType) && "Element type of a VectorType must " "be an integer, floating point, or " "pointer type."); + unsigned PackedEC = EC.getMinNumElements() | ((unsigned)EC.isScalable()<<31); LLVMContextImpl *pImpl = ElementType->getContext().pImpl; VectorType *&Entry = ElementType->getContext().pImpl - ->VectorTypes[std::make_pair(ElementType, NumElements)]; + ->VectorTypes[std::make_pair(ElementType, PackedEC)]; if (!Entry) - Entry = new (pImpl->TypeAllocator) VectorType(ElementType, NumElements); + Entry = new (pImpl->TypeAllocator) VectorType(ElementType, EC); return Entry; } Index: test/Bitcode/compatibility.ll =================================================================== --- test/Bitcode/compatibility.ll +++ test/Bitcode/compatibility.ll @@ -821,6 +821,10 @@ ; CHECK: %t7 = alloca x86_mmx %t8 = alloca %opaquety* ; CHECK: %t8 = alloca %opaquety* + %t9 = alloca <4 x i32> + ; CHECK: %t9 = alloca <4 x i32> + %t10 = alloca + ; CHECK: %t10 = alloca ret void }