]> granicus.if.org Git - llvm/commitdiff
[GlobalISel] Support vector-of-pointers in LLT
authorKristof Beyls <kristof.beyls@arm.com>
Tue, 18 Apr 2017 08:12:45 +0000 (08:12 +0000)
committerKristof Beyls <kristof.beyls@arm.com>
Tue, 18 Apr 2017 08:12:45 +0000 (08:12 +0000)
This fixes PR32471.

As comment 10 on that bug report highlights
(https://bugs.llvm.org//show_bug.cgi?id=32471#c10), there are quite a
few different defendable design tradeoffs that could be made, including
not representing pointers at all in LLT.

I decided to go for representing vector-of-pointer as a concept in LLT,
while keeping the size of the LLT type 64 bits (this is an increase from
48 bits before). My rationale for keeping pointers explicit is that on
some targets probably it's very handy to have the distinction between
pointer and non-pointer (e.g. 68K has a different register bank for
pointers IIRC). If we keep a scalar pointer, it probably is easiest to
also have a vector-of-pointers to keep LLT relatively conceptually clean
and orthogonal, while we don't have a very strong reason to break that
orthogonality. Once we gain more experience on the use of LLT, we can
of course reconsider this direction.

Rejecting vector-of-pointer types in the IRTranslator is also an option
to avoid the crash reported in PR32471, but that is only a very
short-term solution; also needs quite a bit of code tweaks in places,
and is probably fragile. Therefore I didn't consider this the best
option.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@300535 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Support/LowLevelTypeImpl.h
lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
lib/CodeGen/LowLevelType.cpp
lib/Support/LowLevelType.cpp
lib/Target/AArch64/AArch64RegisterBankInfo.cpp
test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll
unittests/CodeGen/LowLevelTypeTest.cpp

index 02df4d806f13bfd163cf85f16b3d88925db56359..e18e58b7b5b232fba60a997ddbac30c0c2d65425 100644 (file)
@@ -39,100 +39,123 @@ class raw_ostream;
 
 class LLT {
 public:
-  enum TypeKind : uint16_t {
-    Invalid,
-    Scalar,
-    Pointer,
-    Vector,
-  };
-
   /// Get a low-level scalar or aggregate "bag of bits".
   static LLT scalar(unsigned SizeInBits) {
     assert(SizeInBits > 0 && "invalid scalar size");
-    return LLT{Scalar, 1, SizeInBits};
+    return LLT{/*isPointer=*/false, /*isVector=*/false, /*NumElements=*/0,
+               SizeInBits, /*AddressSpace=*/0};
   }
 
   /// Get a low-level pointer in the given address space (defaulting to 0).
   static LLT pointer(uint16_t AddressSpace, unsigned SizeInBits) {
-    return LLT{Pointer, AddressSpace, SizeInBits};
+    assert(SizeInBits > 0 && "invalid pointer size");
+    return LLT{/*isPointer=*/true, /*isVector=*/false, /*NumElements=*/0,
+               SizeInBits, AddressSpace};
   }
 
   /// Get a low-level vector of some number of elements and element width.
   /// \p NumElements must be at least 2.
   static LLT vector(uint16_t NumElements, unsigned ScalarSizeInBits) {
     assert(NumElements > 1 && "invalid number of vector elements");
-    return LLT{Vector, NumElements, ScalarSizeInBits};
+    assert(ScalarSizeInBits > 0 && "invalid vector element size");
+    return LLT{/*isPointer=*/false, /*isVector=*/true, NumElements,
+               ScalarSizeInBits, /*AddressSpace=*/0};
   }
 
   /// Get a low-level vector of some number of elements and element type.
   static LLT vector(uint16_t NumElements, LLT ScalarTy) {
     assert(NumElements > 1 && "invalid number of vector elements");
-    assert(ScalarTy.isScalar() && "invalid vector element type");
-    return LLT{Vector, NumElements, ScalarTy.getSizeInBits()};
+    assert(!ScalarTy.isVector() && "invalid vector element type");
+    return LLT{ScalarTy.isPointer(), /*isVector=*/true, NumElements,
+               ScalarTy.getSizeInBits(),
+               ScalarTy.isPointer() ? ScalarTy.getAddressSpace() : 0};
   }
 
-  explicit LLT(TypeKind Kind, uint16_t NumElements, unsigned SizeInBits)
-    : SizeInBits(SizeInBits), ElementsOrAddrSpace(NumElements), Kind(Kind) {
-    assert((Kind != Vector || ElementsOrAddrSpace > 1) &&
-           "invalid number of vector elements");
+  explicit LLT(bool isPointer, bool isVector, uint16_t NumElements,
+               unsigned SizeInBits, unsigned AddressSpace) {
+    init(isPointer, isVector, NumElements, SizeInBits, AddressSpace);
   }
-
-  explicit LLT() : SizeInBits(0), ElementsOrAddrSpace(0), Kind(Invalid) {}
+  explicit LLT() : IsPointer(false), IsVector(false), RawData(0) {}
 
   explicit LLT(MVT VT);
 
-  bool isValid() const { return Kind != Invalid; }
+  bool isValid() const { return RawData != 0; }
 
-  bool isScalar() const { return Kind == Scalar; }
+  bool isScalar() const { return isValid() && !IsPointer && !IsVector; }
 
-  bool isPointer() const { return Kind == Pointer; }
+  bool isPointer() const { return isValid() && IsPointer && !IsVector; }
 
-  bool isVector() const { return Kind == Vector; }
+  bool isVector() const { return isValid() && IsVector; }
 
   /// Returns the number of elements in a vector LLT. Must only be called on
   /// vector types.
   uint16_t getNumElements() const {
-    assert(isVector() && "cannot get number of elements on scalar/aggregate");
-    return ElementsOrAddrSpace;
+    assert(IsVector && "cannot get number of elements on scalar/aggregate");
+    if (!IsPointer)
+      return getFieldValue(VectorElementsFieldInfo);
+    else
+      return getFieldValue(PointerVectorElementsFieldInfo);
   }
 
   /// Returns the total size of the type. Must only be called on sized types.
   unsigned getSizeInBits() const {
     if (isPointer() || isScalar())
-      return SizeInBits;
-    return SizeInBits * ElementsOrAddrSpace;
+      return getScalarSizeInBits();
+    return getScalarSizeInBits() * getNumElements();
   }
 
   unsigned getScalarSizeInBits() const {
-    return SizeInBits;
+    assert(RawData != 0 && "Invalid Type");
+    if (!IsVector) {
+      if (!IsPointer)
+        return getFieldValue(ScalarSizeFieldInfo);
+      else
+        return getFieldValue(PointerSizeFieldInfo);
+    } else {
+      if (!IsPointer)
+        return getFieldValue(VectorSizeFieldInfo);
+      else
+        return getFieldValue(PointerVectorSizeFieldInfo);
+    }
   }
 
   unsigned getAddressSpace() const {
-    assert(isPointer() && "cannot get address space of non-pointer type");
-    return ElementsOrAddrSpace;
+    assert(RawData != 0 && "Invalid Type");
+    assert(IsPointer && "cannot get address space of non-pointer type");
+    if (!IsVector)
+      return getFieldValue(PointerAddressSpaceFieldInfo);
+    else
+      return getFieldValue(PointerVectorAddressSpaceFieldInfo);
   }
 
   /// Returns the vector's element type. Only valid for vector types.
   LLT getElementType() const {
     assert(isVector() && "cannot get element type of scalar/aggregate");
-    return scalar(SizeInBits);
+    if (IsPointer)
+      return pointer(getAddressSpace(), getScalarSizeInBits());
+    else
+      return scalar(getScalarSizeInBits());
   }
 
   /// Get a low-level type with half the size of the original, by halving the
   /// size of the scalar type involved. For example `s32` will become `s16`,
   /// `<2 x s32>` will become `<2 x s16>`.
   LLT halfScalarSize() const {
-    assert(!isPointer() && getScalarSizeInBits() > 1 &&
+    assert(!IsPointer && getScalarSizeInBits() > 1 &&
            getScalarSizeInBits() % 2 == 0 && "cannot half size of this type");
-    return LLT{Kind, ElementsOrAddrSpace, SizeInBits / 2};
+    return LLT{/*isPointer=*/false, IsVector ? true : false,
+               IsVector ? getNumElements() : (uint16_t)0,
+               getScalarSizeInBits() / 2, /*AddressSpace=*/0};
   }
 
   /// Get a low-level type with twice the size of the original, by doubling the
   /// size of the scalar type involved. For example `s32` will become `s64`,
   /// `<2 x s32>` will become `<2 x s64>`.
   LLT doubleScalarSize() const {
-    assert(!isPointer() && "cannot change size of this type");
-    return LLT{Kind, ElementsOrAddrSpace, SizeInBits * 2};
+    assert(!IsPointer && "cannot change size of this type");
+    return LLT{/*isPointer=*/false, IsVector ? true : false,
+               IsVector ? getNumElements() : (uint16_t)0,
+               getScalarSizeInBits() * 2, /*AddressSpace=*/0};
   }
 
   /// Get a low-level type with half the size of the original, by halving the
@@ -140,13 +163,13 @@ public:
   /// a vector type with an even number of elements. For example `<4 x s32>`
   /// will become `<2 x s32>`, `<2 x s32>` will become `s32`.
   LLT halfElements() const {
-    assert(isVector() && ElementsOrAddrSpace % 2 == 0 &&
-           "cannot half odd vector");
-    if (ElementsOrAddrSpace == 2)
-      return scalar(SizeInBits);
+    assert(isVector() && getNumElements() % 2 == 0 && "cannot half odd vector");
+    if (getNumElements() == 2)
+      return scalar(getScalarSizeInBits());
 
-    return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace / 2),
-               SizeInBits};
+    return LLT{/*isPointer=*/false, /*isVector=*/true,
+               (uint16_t)(getNumElements() / 2), getScalarSizeInBits(),
+               /*AddressSpace=*/0};
   }
 
   /// Get a low-level type with twice the size of the original, by doubling the
@@ -154,25 +177,105 @@ public:
   /// a vector type. For example `<2 x s32>` will become `<4 x s32>`. Doubling
   /// the number of elements in sN produces <2 x sN>.
   LLT doubleElements() const {
-    assert(!isPointer() && "cannot double elements in pointer");
-    return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace * 2),
-               SizeInBits};
+    return LLT{IsPointer ? true : false, /*isVector=*/true,
+               (uint16_t)(getNumElements() * 2), getScalarSizeInBits(),
+               IsPointer ? getAddressSpace() : 0};
   }
 
   void print(raw_ostream &OS) const;
 
   bool operator==(const LLT &RHS) const {
-    return Kind == RHS.Kind && SizeInBits == RHS.SizeInBits &&
-           ElementsOrAddrSpace == RHS.ElementsOrAddrSpace;
+    return IsPointer == RHS.IsPointer && IsVector == RHS.IsVector &&
+           RHS.RawData == RawData;
   }
 
   bool operator!=(const LLT &RHS) const { return !(*this == RHS); }
 
   friend struct DenseMapInfo<LLT>;
+
 private:
-  unsigned SizeInBits;
-  uint16_t ElementsOrAddrSpace;
-  TypeKind Kind;
+  /// LLT is packed into 64 bits as follows:
+  /// isPointer : 1
+  /// isVector  : 1
+  /// with 62 bits remaining for Kind-specific data, packed in bitfields
+  /// as described below. As there isn't a simple portable way to pack bits
+  /// into bitfields, here the different fields in the packed structure is
+  /// described in static const *Field variables. Each of these variables
+  /// is a 2-element array, with the first element describing the bitfield size
+  /// and the second element describing the bitfield offset.
+  typedef int BitFieldInfo[2];
+  ///
+  /// This is how the bitfields are packed per Kind:
+  /// * Invalid:
+  ///   gets encoded as RawData == 0, as that is an invalid encoding, since for
+  ///   valid encodings, SizeInBits/SizeOfElement must be larger than 0.
+  /// * Non-pointer scalar (isPointer == 0 && isVector == 0):
+  ///   SizeInBits: 32;
+  static const constexpr BitFieldInfo ScalarSizeFieldInfo{32, 0};
+  /// * Pointer (isPointer == 1 && isVector == 0):
+  ///   SizeInBits: 16;
+  ///   AddressSpace: 23;
+  static const constexpr BitFieldInfo PointerSizeFieldInfo{16, 0};
+  static const constexpr BitFieldInfo PointerAddressSpaceFieldInfo{
+      23, PointerSizeFieldInfo[0] + PointerSizeFieldInfo[1]};
+  /// * Vector-of-non-pointer (isPointer == 0 && isVector == 1):
+  ///   NumElements: 16;
+  ///   SizeOfElement: 32;
+  static const constexpr BitFieldInfo VectorElementsFieldInfo{16, 0};
+  static const constexpr BitFieldInfo VectorSizeFieldInfo{
+      32, VectorElementsFieldInfo[0] + VectorElementsFieldInfo[1]};
+  /// * Vector-of-pointer (isPointer == 1 && isVector == 1):
+  ///   NumElements: 16;
+  ///   SizeOfElement: 16;
+  ///   AddressSpace: 23;
+  static const constexpr BitFieldInfo PointerVectorElementsFieldInfo{16, 0};
+  static const constexpr BitFieldInfo PointerVectorSizeFieldInfo{
+      16,
+      PointerVectorElementsFieldInfo[1] + PointerVectorElementsFieldInfo[0]};
+  static const constexpr BitFieldInfo PointerVectorAddressSpaceFieldInfo{
+      23, PointerVectorSizeFieldInfo[1] + PointerVectorSizeFieldInfo[0]};
+
+  uint64_t IsPointer : 1;
+  uint64_t IsVector : 1;
+  uint64_t RawData : 62;
+
+  static uint64_t getMask(const BitFieldInfo FieldInfo) {
+    const int FieldSizeInBits = FieldInfo[0];
+    return (((uint64_t)1) << FieldSizeInBits) - 1;
+  }
+  static uint64_t maskAndShift(uint64_t Val, uint64_t Mask, uint8_t Shift) {
+    assert(Val <= Mask && "Value too large for field");
+    return (Val & Mask) << Shift;
+  }
+  static uint64_t maskAndShift(uint64_t Val, const BitFieldInfo FieldInfo) {
+    return maskAndShift(Val, getMask(FieldInfo), FieldInfo[1]);
+  }
+  uint64_t getFieldValue(const BitFieldInfo FieldInfo) const {
+    return getMask(FieldInfo) & (RawData >> FieldInfo[1]);
+  }
+
+  void init(bool IsPointer, bool IsVector, uint16_t NumElements,
+            unsigned SizeInBits, unsigned AddressSpace) {
+    this->IsPointer = IsPointer;
+    this->IsVector = IsVector;
+    if (!IsVector) {
+      if (!IsPointer)
+        RawData = maskAndShift(SizeInBits, ScalarSizeFieldInfo);
+      else
+        RawData = maskAndShift(SizeInBits, PointerSizeFieldInfo) |
+                  maskAndShift(AddressSpace, PointerAddressSpaceFieldInfo);
+    } else {
+      assert(NumElements > 1 && "invalid number of vector elements");
+      if (!IsPointer)
+        RawData = maskAndShift(NumElements, VectorElementsFieldInfo) |
+                  maskAndShift(SizeInBits, VectorSizeFieldInfo);
+      else
+        RawData =
+            maskAndShift(NumElements, PointerVectorElementsFieldInfo) |
+            maskAndShift(SizeInBits, PointerVectorSizeFieldInfo) |
+            maskAndShift(AddressSpace, PointerVectorAddressSpaceFieldInfo);
+    }
+  }
 };
 
 inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) {
@@ -182,14 +285,18 @@ inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) {
 
 template<> struct DenseMapInfo<LLT> {
   static inline LLT getEmptyKey() {
-    return LLT{LLT::Invalid, 0, -1u};
+    LLT Invalid;
+    Invalid.IsPointer = true;
+    return Invalid;
   }
   static inline LLT getTombstoneKey() {
-    return LLT{LLT::Invalid, 0, -2u};
+    LLT Invalid;
+    Invalid.IsVector = true;
+    return Invalid;
   }
   static inline unsigned getHashValue(const LLT &Ty) {
-    uint64_t Val = ((uint64_t)Ty.SizeInBits << 32) |
-                   ((uint64_t)Ty.ElementsOrAddrSpace << 16) | (uint64_t)Ty.Kind;
+    uint64_t Val = ((uint64_t)Ty.RawData) << 2 | ((uint64_t)Ty.IsPointer) << 1 |
+                   ((uint64_t)Ty.IsVector);
     return DenseMapInfo<uint64_t>::getHashValue(Val);
   }
   static bool isEqual(const LLT &LHS, const LLT &RHS) {
index 8d1a263395a0e913d52825e00883e16b6f6ba4e1..54ef7e5c5a1b15470f6dd4647846fabc3bb8cbb3 100644 (file)
@@ -592,7 +592,7 @@ MachineInstrBuilder MachineIRBuilder::buildInsertVectorElement(unsigned Res,
   LLT EltTy = MRI->getType(Elt);
   LLT IdxTy = MRI->getType(Idx);
   assert(ResTy.isVector() && ValTy.isVector() && "invalid operand type");
-  assert(EltTy.isScalar() && IdxTy.isScalar() && "invalid operand type");
+  assert(IdxTy.isScalar() && "invalid operand type");
   assert(ResTy.getNumElements() == ValTy.getNumElements() && "type mismatch");
   assert(ResTy.getElementType() == EltTy && "type mismatch");
 #endif
@@ -612,7 +612,8 @@ MachineInstrBuilder MachineIRBuilder::buildExtractVectorElement(unsigned Res,
   LLT ValTy = MRI->getType(Val);
   LLT IdxTy = MRI->getType(Idx);
   assert(ValTy.isVector() && "invalid operand type");
-  assert(ResTy.isScalar() && IdxTy.isScalar() && "invalid operand type");
+  assert((ResTy.isScalar() || ResTy.isPointer()) && "invalid operand type");
+  assert(IdxTy.isScalar() && "invalid operand type");
   assert(ValTy.getElementType() == ResTy && "type mismatch");
 #endif
 
index c4b9068fa905ab29bc2d1a02381367d2f1ad1a90..1c682e72fa49145aaf795fb67f0b271683d6d9f0 100644 (file)
@@ -21,10 +21,10 @@ using namespace llvm;
 LLT llvm::getLLTForType(Type &Ty, const DataLayout &DL) {
   if (auto VTy = dyn_cast<VectorType>(&Ty)) {
     auto NumElements = VTy->getNumElements();
-    auto ScalarSizeInBits = VTy->getElementType()->getPrimitiveSizeInBits();
+    LLT ScalarTy = getLLTForType(*VTy->getElementType(), DL);
     if (NumElements == 1)
-      return LLT::scalar(ScalarSizeInBits);
-    return LLT::vector(NumElements, ScalarSizeInBits);
+      return ScalarTy;
+    return LLT::vector(NumElements, ScalarTy);
   } else if (auto PTy = dyn_cast<PointerType>(&Ty)) {
     return LLT::pointer(PTy->getAddressSpace(), DL.getTypeSizeInBits(&Ty));
   } else if (Ty.isSized()) {
index 4290d69cd197d0645688b91b51be7e1b56f05527..648a5ea7c07532d390b82478a248585a82edce08 100644 (file)
@@ -18,25 +18,25 @@ using namespace llvm;
 
 LLT::LLT(MVT VT) {
   if (VT.isVector()) {
-    SizeInBits = VT.getVectorElementType().getSizeInBits();
-    ElementsOrAddrSpace = VT.getVectorNumElements();
-    Kind = ElementsOrAddrSpace == 1 ? Scalar : Vector;
+    init(/*isPointer=*/false, VT.getVectorNumElements() > 1,
+         VT.getVectorNumElements(), VT.getVectorElementType().getSizeInBits(),
+         /*AddressSpace=*/0);
   } else if (VT.isValid()) {
     // Aggregates are no different from real scalars as far as GlobalISel is
     // concerned.
-    Kind = Scalar;
-    SizeInBits = VT.getSizeInBits();
-    ElementsOrAddrSpace = 1;
-    assert(SizeInBits != 0 && "invalid zero-sized type");
+    assert(VT.getSizeInBits() != 0 && "invalid zero-sized type");
+    init(/*isPointer=*/false, /*isVector=*/false, /*NumElements=*/0,
+         VT.getSizeInBits(), /*AddressSpace=*/0);
   } else {
-    Kind = Invalid;
-    SizeInBits = ElementsOrAddrSpace = 0;
+    IsPointer = false;
+    IsVector = false;
+    RawData = 0;
   }
 }
 
 void LLT::print(raw_ostream &OS) const {
   if (isVector())
-    OS << "<" << ElementsOrAddrSpace << " x s" << SizeInBits << ">";
+    OS << "<" << getNumElements() << " x " << getElementType() << ">";
   else if (isPointer())
     OS << "p" << getAddressSpace();
   else if (isValid()) {
@@ -45,3 +45,12 @@ void LLT::print(raw_ostream &OS) const {
   } else
     llvm_unreachable("trying to print an invalid type");
 }
+
+const LLT::BitFieldInfo LLT::ScalarSizeFieldInfo;
+const LLT::BitFieldInfo LLT::PointerSizeFieldInfo;
+const LLT::BitFieldInfo LLT::PointerAddressSpaceFieldInfo;
+const LLT::BitFieldInfo LLT::VectorElementsFieldInfo;
+const LLT::BitFieldInfo LLT::VectorSizeFieldInfo;
+const LLT::BitFieldInfo LLT::PointerVectorElementsFieldInfo;
+const LLT::BitFieldInfo LLT::PointerVectorSizeFieldInfo;
+const LLT::BitFieldInfo LLT::PointerVectorAddressSpaceFieldInfo;
index 20a5979f9b4b7115966426587083ea121c11c481..6f9021c4a030c3cd524918d5ab7eb73bcd168a98 100644 (file)
@@ -482,7 +482,7 @@ AArch64RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
   SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands);
   for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
     auto &MO = MI.getOperand(Idx);
-    if (!MO.isReg())
+    if (!MO.isReg() || !MO.getReg())
       continue;
 
     LLT Ty = MRI.getType(MO.getReg());
@@ -537,7 +537,7 @@ AArch64RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
       InstructionMapping{DefaultMappingID, Cost, nullptr, NumOperands};
   SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
   for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
-    if (MI.getOperand(Idx).isReg()) {
+    if (MI.getOperand(Idx).isReg() && MI.getOperand(Idx).getReg()) {
       auto Mapping = getValueMapping(OpRegBankIdx[Idx], OpSize[Idx]);
       if (!Mapping->isValid())
         return InstructionMapping();
index e40199d82c9ddb5df8e97be4d9cdb96cfa094764..71ea9d54f647af11be6b4f11072299713e7ea70f 100644 (file)
@@ -154,3 +154,19 @@ continue:
 define fp128 @test_quad_dump() {
   ret fp128 0xL00000000000000004000000000000000
 }
+
+; FALLBACK-WITH-REPORT-ERR: remark: <unknown>:0:0: unable to legalize instruction: %vreg0<def>(p0) = G_EXTRACT_VECTOR_ELT %vreg1, %vreg2; (in function: vector_of_pointers_extractelement)
+; FALLBACK-WITH-REPORT-ERR: warning: Instruction selection used fallback path for vector_of_pointers_extractelement
+; FALLBACK-WITH-REPORT-OUT-LABEL: vector_of_pointers_extractelement:
+define void @vector_of_pointers_extractelement() {
+  %dummy = extractelement <2 x i16*> undef, i32 0
+  ret void
+}
+
+; FALLBACK-WITH-REPORT-ERR: remark: <unknown>:0:0: unable to legalize instruction: %vreg0<def>(<2 x p0>) = G_INSERT_VECTOR_ELT %vreg1, %vreg2, %vreg3; (in function: vector_of_pointers_insertelement
+; FALLBACK-WITH-REPORT-ERR: warning: Instruction selection used fallback path for vector_of_pointers_insertelement
+; FALLBACK-WITH-REPORT-OUT-LABEL: vector_of_pointers_insertelement:
+define void @vector_of_pointers_insertelement() {
+  %dummy = insertelement <2 x i16*> undef, i16* null, i32 0
+  ret void
+}
index 67113005a46a1a6ffcee459f0db752b0d493d855..428d6b93f790baa3d6666631858369ddaa0866c4 100644 (file)
@@ -171,6 +171,7 @@ TEST(LowLevelTypeTest, Pointer) {
 
   for (unsigned AS : {0U, 1U, 127U, 0xffffU}) {
     const LLT Ty = LLT::pointer(AS, DL.getPointerSizeInBits(AS));
+    const LLT VTy = LLT::vector(4, Ty);
 
     // Test kind.
     ASSERT_TRUE(Ty.isValid());
@@ -179,16 +180,26 @@ TEST(LowLevelTypeTest, Pointer) {
     ASSERT_FALSE(Ty.isScalar());
     ASSERT_FALSE(Ty.isVector());
 
+    ASSERT_TRUE(VTy.isValid());
+    ASSERT_TRUE(VTy.isVector());
+    ASSERT_TRUE(VTy.getElementType().isPointer());
+
     // Test addressspace.
     EXPECT_EQ(AS, Ty.getAddressSpace());
+    EXPECT_EQ(AS, VTy.getElementType().getAddressSpace());
 
     // Test equality operators.
     EXPECT_TRUE(Ty == Ty);
     EXPECT_FALSE(Ty != Ty);
+    EXPECT_TRUE(VTy == VTy);
+    EXPECT_FALSE(VTy != VTy);
 
     // Test Type->LLT conversion.
     Type *IRTy = PointerType::get(IntegerType::get(C, 8), AS);
     EXPECT_EQ(Ty, getLLTForType(*IRTy, DL));
+    Type *IRVTy =
+        VectorType::get(PointerType::get(IntegerType::get(C, 8), AS), 4);
+    EXPECT_EQ(VTy, getLLTForType(*IRVTy, DL));
   }
 }