Relax the restrictions on vector of pointer types, and vector getelementptr.
authorDuncan Sands <baldrick@free.fr>
Tue, 13 Nov 2012 12:59:33 +0000 (12:59 +0000)
committerDuncan Sands <baldrick@free.fr>
Tue, 13 Nov 2012 12:59:33 +0000 (12:59 +0000)
Previously in a vector of pointers, the pointer couldn't be any pointer type,
it had to be a pointer to an integer or floating point type.  This is a hassle
for dragonegg because the GCC vectorizer happily produces vectors of pointers
where the pointer is a pointer to a struct or whatever.  Vector getelementptr
was restricted to just one index, but now that vectors of pointers can have
any pointer type it is more natural to allow arbitrary vector getelementptrs.
There is however the issue of struct GEPs, where if each lane chose different
struct fields then from that point on each lane will be working down into
unrelated types.  This seems like too much pain for too little gain, so when
you have a vector struct index all the elements are required to be the same.

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

14 files changed:
docs/LangRef.html
include/llvm/Constant.h
lib/AsmParser/LLParser.cpp
lib/Bitcode/Writer/ValueEnumerator.cpp
lib/VMCore/Constants.cpp
lib/VMCore/Instructions.cpp
lib/VMCore/Type.cpp
lib/VMCore/Verifier.cpp
test/Assembler/getelementptr.ll
test/Assembler/getelementptr_vec_idx1.ll [new file with mode: 0644]
test/Assembler/getelementptr_vec_idx2.ll [new file with mode: 0644]
test/Assembler/getelementptr_vec_idx3.ll [new file with mode: 0644]
test/Assembler/getelementptr_vec_struct.ll [new file with mode: 0644]
test/Transforms/LoopVectorize/gcc-examples.ll

index ed47f1f00ed5582dd9220dc1aa21db61b5d64238..cdb76848e2d4a7f5bfed4f68acecf0fd8e5353ba 100644 (file)
@@ -5419,9 +5419,11 @@ specified by the <var>operation</var> argument:</p>
 
 <p>The type of each index argument depends on the type it is indexing into.
    When indexing into a (optionally packed) structure, only <tt>i32</tt>
-   integer <b>constants</b> are allowed.  When indexing into an array, pointer
-   or vector, integers of any width are allowed, and they are not required to be
-   constant.  These integers are treated as signed values where relevant.</p>
+   integer <b>constants</b> are allowed (when using a vector of indices they
+   must all be the <b>same</b> <tt>i32</tt> integer constant).  When indexing
+   into an array, pointer or vector, integers of any width are allowed, and
+   they are not required to be constant.  These integers are treated as signed
+   values where relevant.</p>
 
 <p>For example, let's consider a C code fragment and how it gets compiled to
    LLVM:</p>
@@ -5520,9 +5522,8 @@ define i32* @foo(%struct.ST* %s) {
     %iptr = getelementptr [10 x i32]* @arr, i16 0, i16 0
 </pre>
 
-<p>In cases where the pointer argument is a vector of pointers, only a
-   single index may be used, and the number of vector elements has to be
-   the same.  For example: </p>
+<p>In cases where the pointer argument is a vector of pointers, each index must
+   be a vector with the same number of elements.  For example: </p>
 <pre class="doc_code">
  %A = getelementptr <4 x i8*> %ptrs, <4 x i64> %offsets,
 </pre>
index 7fecf4c7b4564d8517f9596c1c259babe2d35375..bbd1b1a6e2c80ff6de5678f1658b21bd7c95ae1e 100644 (file)
@@ -97,7 +97,15 @@ public:
   /// 'this' is a constant expr.
   Constant *getAggregateElement(unsigned Elt) const;
   Constant *getAggregateElement(Constant *Elt) const;
-  
+
+  /// getSplatValue - If this is a splat vector constant, meaning that all of
+  /// the elements have the same value, return that value. Otherwise return 0.
+  Constant *getSplatValue() const;
+
+  /// If C is a constant integer then return its value, otherwise C must be a
+  /// vector of constant integers, all equal, and the common value is returned.
+  const APInt &getUniqueInteger() const;
+
   /// destroyConstant - Called if some element of this constant is no longer
   /// valid.  At this point only other constants may be on the use_list for this
   /// constant.  Any constants on our Use list must also be destroy'd.  The
index ac803c57833467c33168b6bfefe6195fa526dd95..de404728be6c73e0cf1480b2e5d4cce66803cc68 100644 (file)
@@ -1697,8 +1697,7 @@ bool LLParser::ParseArrayVectorType(Type *&Result, bool isVector) {
     if ((unsigned)Size != Size)
       return Error(SizeLoc, "size too large for vector");
     if (!VectorType::isValidElementType(EltTy))
-      return Error(TypeLoc,
-       "vector element type must be fp, integer or a pointer to these types");
+      return Error(TypeLoc, "invalid vector element type");
     Result = VectorType::get(EltTy, unsigned(Size));
   } else {
     if (!ArrayType::isValidElementType(EltTy))
@@ -4032,9 +4031,6 @@ int LLParser::ParseGetElementPtr(Instruction *&Inst, PerFunctionState &PFS) {
     Indices.push_back(Val);
   }
 
-  if (Val && Val->getType()->isVectorTy() && Indices.size() != 1)
-    return Error(EltLoc, "vector getelementptrs must have a single index");
-
   if (!GetElementPtrInst::getIndexedType(Ptr->getType(), Indices))
     return Error(Loc, "invalid getelementptr indices");
   Inst = GetElementPtrInst::Create(Ptr, Indices);
index 1ed9004eb5a16c0a173f246089796b6c8fe97483..cf3839d4b0a6bc6853f81d779adcf7ead99cf24d 100644 (file)
@@ -24,8 +24,8 @@
 #include <algorithm>
 using namespace llvm;
 
-static bool isIntegerValue(const std::pair<const Value*, unsigned> &V) {
-  return V.first->getType()->isIntegerTy();
+static bool isIntOrIntVectorValue(const std::pair<const Value*, unsigned> &V) {
+  return V.first->getType()->isIntOrIntVectorTy();
 }
 
 /// ValueEnumerator - Enumerate module-level information.
@@ -192,10 +192,11 @@ void ValueEnumerator::OptimizeConstants(unsigned CstStart, unsigned CstEnd) {
   CstSortPredicate P(*this);
   std::stable_sort(Values.begin()+CstStart, Values.begin()+CstEnd, P);
 
-  // Ensure that integer constants are at the start of the constant pool.  This
-  // is important so that GEP structure indices come before gep constant exprs.
+  // Ensure that integer and vector of integer constants are at the start of the
+  // constant pool.  This is important so that GEP structure indices come before
+  // gep constant exprs.
   std::partition(Values.begin()+CstStart, Values.begin()+CstEnd,
-                 isIntegerValue);
+                 isIntOrIntVectorValue);
 
   // Rebuild the modified portion of ValueMap.
   for (; CstStart != CstEnd; ++CstStart)
index a4e21e16b3fcfb31f2e9774656738f34cf4eb0f6..f96fb1d401917bf0a3919bf2b1c900b7d6c6b474 100644 (file)
@@ -1213,6 +1213,19 @@ void ConstantVector::destroyConstant() {
   destroyConstantImpl();
 }
 
+/// getSplatValue - If this is a splat vector constant, meaning that all of
+/// the elements have the same value, return that value. Otherwise return 0.
+Constant *Constant::getSplatValue() const {
+  assert(this->getType()->isVectorTy() && "Only valid for vectors!");
+  if (isa<ConstantAggregateZero>(this))
+    return getNullValue(this->getType()->getVectorElementType());
+  if (const ConstantDataVector *CV = dyn_cast<ConstantDataVector>(this))
+    return CV->getSplatValue();
+  if (const ConstantVector *CV = dyn_cast<ConstantVector>(this))
+    return CV->getSplatValue();
+  return 0;
+}
+
 /// getSplatValue - If this is a splat constant, where all of the
 /// elements have the same value, return that value. Otherwise return null.
 Constant *ConstantVector::getSplatValue() const {
@@ -1225,6 +1238,18 @@ Constant *ConstantVector::getSplatValue() const {
   return Elt;
 }
 
+/// If C is a constant integer then return its value, otherwise C must be a
+/// vector of constant integers, all equal, and the common value is returned.
+const APInt &Constant::getUniqueInteger() const {
+  if (const ConstantInt *CI = dyn_cast<ConstantInt>(this))
+    return CI->getValue();
+  assert(this->getSplatValue() && "Doesn't contain a unique integer!");
+  const Constant *C = this->getAggregateElement(0U);
+  assert(C && isa<ConstantInt>(C) && "Not a vector of numbers!");
+  return cast<ConstantInt>(C)->getValue();
+}
+
+
 //---- ConstantPointerNull::get() implementation.
 //
 
@@ -1739,6 +1764,9 @@ Constant *ConstantExpr::getSelect(Constant *C, Constant *V1, Constant *V2) {
 
 Constant *ConstantExpr::getGetElementPtr(Constant *C, ArrayRef<Value *> Idxs,
                                          bool InBounds) {
+  assert(C->getType()->isPtrOrPtrVectorTy() &&
+         "Non-pointer type for constant GetElementPtr expression");
+
   if (Constant *FC = ConstantFoldGetElementPtr(C, InBounds, Idxs))
     return FC;          // Fold a few common cases.
 
@@ -1747,15 +1775,22 @@ Constant *ConstantExpr::getGetElementPtr(Constant *C, ArrayRef<Value *> Idxs,
   assert(Ty && "GEP indices invalid!");
   unsigned AS = C->getType()->getPointerAddressSpace();
   Type *ReqTy = Ty->getPointerTo(AS);
+  if (VectorType *VecTy = dyn_cast<VectorType>(C->getType()))
+    ReqTy = VectorType::get(ReqTy, VecTy->getNumElements());
 
-  assert(C->getType()->isPointerTy() &&
-         "Non-pointer type for constant GetElementPtr expression");
   // Look up the constant in the table first to ensure uniqueness
   std::vector<Constant*> ArgVec;
   ArgVec.reserve(1 + Idxs.size());
   ArgVec.push_back(C);
-  for (unsigned i = 0, e = Idxs.size(); i != e; ++i)
+  for (unsigned i = 0, e = Idxs.size(); i != e; ++i) {
+    assert(Idxs[i]->getType()->isVectorTy() == ReqTy->isVectorTy() &&
+           "getelementptr index type missmatch");
+    assert((!Idxs[i]->getType()->isVectorTy() ||
+            ReqTy->getVectorNumElements() ==
+            Idxs[i]->getType()->getVectorNumElements()) &&
+           "getelementptr index type missmatch");
     ArgVec.push_back(cast<Constant>(Idxs[i]));
+  }
   const ExprMapKeyType Key(Instruction::GetElementPtr, ArgVec, 0,
                            InBounds ? GEPOperator::IsInBounds : 0);
 
index 94bd2a15632d0b1587e3a5393054a2dd522c3149..ca7cd4eb978d6e4cf8e0fce83a5230dfb5f496ca 100644 (file)
@@ -1353,16 +1353,7 @@ GetElementPtrInst::GetElementPtrInst(const GetElementPtrInst &GEPI)
 ///
 template <typename IndexTy>
 static Type *getIndexedTypeInternal(Type *Ptr, ArrayRef<IndexTy> IdxList) {
-  if (Ptr->isVectorTy()) {
-    assert(IdxList.size() == 1 &&
-      "GEP with vector pointers must have a single index");
-    PointerType *PTy = dyn_cast<PointerType>(
-        cast<VectorType>(Ptr)->getElementType());
-    assert(PTy && "Gep with invalid vector pointer found");
-    return PTy->getElementType();
-  }
-
-  PointerType *PTy = dyn_cast<PointerType>(Ptr);
+  PointerType *PTy = dyn_cast<PointerType>(Ptr->getScalarType());
   if (!PTy) return 0;   // Type isn't a pointer type!
   Type *Agg = PTy->getElementType();
 
index 1656ab2cab3a8b86bc4bdb0ef834fd017df339b3..4d75a7e060f26d956bfb4fa78202835bb5d8955c 100644 (file)
@@ -629,11 +629,12 @@ StructType *Module::getTypeByName(StringRef Name) const {
 
 Type *CompositeType::getTypeAtIndex(const Value *V) {
   if (StructType *STy = dyn_cast<StructType>(this)) {
-    unsigned Idx = (unsigned)cast<ConstantInt>(V)->getZExtValue();
+    unsigned Idx =
+      (unsigned)cast<Constant>(V)->getUniqueInteger().getZExtValue();
     assert(indexValid(Idx) && "Invalid structure index!");
     return STy->getElementType(Idx);
   }
-  
+
   return cast<SequentialType>(this)->getElementType();
 }
 Type *CompositeType::getTypeAtIndex(unsigned Idx) {
@@ -646,15 +647,19 @@ Type *CompositeType::getTypeAtIndex(unsigned Idx) {
 }
 bool CompositeType::indexValid(const Value *V) const {
   if (const StructType *STy = dyn_cast<StructType>(this)) {
-    // Structure indexes require 32-bit integer constants.
-    if (V->getType()->isIntegerTy(32))
-      if (const ConstantInt *CU = dyn_cast<ConstantInt>(V))
-        return CU->getZExtValue() < STy->getNumElements();
-    return false;
+    // Structure indexes require (vectors of) 32-bit integer constants.  In the
+    // vector case all of the indices must be equal.
+    if (!V->getType()->getScalarType()->isIntegerTy(32))
+      return false;
+    const Constant *C = dyn_cast<Constant>(V);
+    if (C && V->getType()->isVectorTy())
+      C = C->getSplatValue();
+    const ConstantInt *CU = dyn_cast_or_null<ConstantInt>(C);
+    return CU && CU->getZExtValue() < STy->getNumElements();
   }
-  
+
   // Sequential types can be indexed by any integer.
-  return V->getType()->isIntegerTy();
+  return V->getType()->isIntOrIntVectorTy();
 }
 
 bool CompositeType::indexValid(unsigned Idx) const {
@@ -717,9 +722,8 @@ VectorType *VectorType::get(Type *elementType, unsigned NumElements) {
 }
 
 bool VectorType::isValidElementType(Type *ElemTy) {
-  if (PointerType *PTy = dyn_cast<PointerType>(ElemTy))
-    ElemTy = PTy->getElementType();
-  return ElemTy->isIntegerTy() || ElemTy->isFloatingPointTy();
+  return ElemTy->isIntegerTy() || ElemTy->isFloatingPointTy() ||
+    ElemTy->isPointerTy();
 }
 
 //===----------------------------------------------------------------------===//
index eb40b09d29f70bba36d8063103c1553c954d0a6e..3782957f3b3dc62c1e585f3728fa634cec74c6ca 100644 (file)
@@ -1375,34 +1375,31 @@ void Verifier::visitGetElementPtrInst(GetElementPtrInst &GEP) {
     "GEP base pointer is not a vector or a vector of pointers", &GEP);
   Assert1(cast<PointerType>(TargetTy)->getElementType()->isSized(),
           "GEP into unsized type!", &GEP);
+  Assert1(GEP.getPointerOperandType()->isVectorTy() ==
+          GEP.getType()->isVectorTy(), "Vector GEP must return a vector value",
+          &GEP);
 
   SmallVector<Value*, 16> Idxs(GEP.idx_begin(), GEP.idx_end());
   Type *ElTy =
     GetElementPtrInst::getIndexedType(GEP.getPointerOperandType(), Idxs);
   Assert1(ElTy, "Invalid indices for GEP pointer type!", &GEP);
 
-  if (GEP.getPointerOperandType()->isPointerTy()) {
-    // Validate GEPs with scalar indices.
-    Assert2(GEP.getType()->isPointerTy() &&
-           cast<PointerType>(GEP.getType())->getElementType() == ElTy,
-           "GEP is not of right type for indices!", &GEP, ElTy);
-  } else {
-    // Validate GEPs with a vector index.
-    Assert1(Idxs.size() == 1, "Invalid number of indices!", &GEP);
-    Value *Index = Idxs[0];
-    Type  *IndexTy = Index->getType();
-    Assert1(IndexTy->isVectorTy(),
-      "Vector GEP must have vector indices!", &GEP);
-    Assert1(GEP.getType()->isVectorTy(),
-      "Vector GEP must return a vector value", &GEP);
-    Type *ElemPtr = cast<VectorType>(GEP.getType())->getElementType();
-    Assert1(ElemPtr->isPointerTy(),
-      "Vector GEP pointer operand is not a pointer!", &GEP);
-    unsigned IndexWidth = cast<VectorType>(IndexTy)->getNumElements();
-    unsigned GepWidth = cast<VectorType>(GEP.getType())->getNumElements();
-    Assert1(IndexWidth == GepWidth, "Invalid GEP index vector width", &GEP);
-    Assert1(ElTy == cast<PointerType>(ElemPtr)->getElementType(),
-      "Vector GEP type does not match pointer type!", &GEP);
+  Assert2(GEP.getType()->getScalarType()->isPointerTy() &&
+          cast<PointerType>(GEP.getType()->getScalarType())->getElementType()
+          == ElTy, "GEP is not of right type for indices!", &GEP, ElTy);
+
+  if (GEP.getPointerOperandType()->isVectorTy()) {
+    // Additional checks for vector GEPs.
+    unsigned GepWidth = GEP.getPointerOperandType()->getVectorNumElements();
+    Assert1(GepWidth == GEP.getType()->getVectorNumElements(),
+            "Vector GEP result width doesn't match operand's", &GEP);
+    for (unsigned i = 0, e = Idxs.size(); i != e; ++i) {
+      Type *IndexTy = Idxs[i]->getType();
+      Assert1(IndexTy->isVectorTy(),
+              "Vector GEP must have vector indices!", &GEP);
+      unsigned IndexWidth = IndexTy->getVectorNumElements();
+      Assert1(IndexWidth == GepWidth, "Invalid GEP index vector width", &GEP);
+    }
   }
   visitInstruction(GEP);
 }
index ce6866d54417855a8f0bfd95516df25ef529ee9f..af03fca6d2c1909bbbcee8a56c006ce46b49eb83 100644 (file)
@@ -7,12 +7,12 @@
 @C = global i32* getelementptr ([2 x [3 x [5 x [7 x i32]]]]* @A, i64 3, i64 2, i64 0, i64 0, i64 7523)
 ; CHECK: @C = global i32* getelementptr ([2 x [3 x [5 x [7 x i32]]]]* @A, i64 39, i64 1, i64 1, i64 4, i64 5)
 
-;; Verify that i16 indices work.
+; Verify that i16 indices work.
 @x = external global {i32, i32}
 @y = global i32* getelementptr ({ i32, i32 }* @x, i16 42, i32 0)
 ; CHECK: @y = global i32* getelementptr ({ i32, i32 }* @x, i16 42, i32 0)
 
-; see if i92 indices work too.
+; See if i92 indices work too.
 define i32 *@test({i32, i32}* %t, i92 %n) {
 ; CHECK: @test
 ; CHECK: %B = getelementptr { i32, i32 }* %t, i92 %n, i32 0
@@ -20,3 +20,18 @@ define i32 *@test({i32, i32}* %t, i92 %n) {
   ret i32* %B
 }
 
+; Verify that constant expression vector GEPs work.
+
+@z = global <2 x i32*> getelementptr (<2 x [3 x {i32, i32}]*> zeroinitializer, <2 x i32> <i32 1, i32 2>, <2 x i32> <i32 2, i32 3>, <2 x i32> <i32 1, i32 1>)
+
+; Verify that struct GEP works with a vector of pointers.
+define <2 x i32*> @test7(<2 x {i32, i32}*> %a) {
+  %w = getelementptr <2 x {i32, i32}*> %a, <2 x i32> <i32 5, i32 9>, <2 x i32> zeroinitializer
+  ret <2 x i32*> %w
+}
+
+; Verify that array GEP works with a vector of pointers.
+define <2 x i8*> @test8(<2 x [2 x i8]*> %a) {
+  %w = getelementptr <2 x  [2 x i8]*> %a, <2 x i32> <i32 0, i32 0>, <2 x i8> <i8 0, i8 1>
+  ret <2 x i8*> %w
+}
diff --git a/test/Assembler/getelementptr_vec_idx1.ll b/test/Assembler/getelementptr_vec_idx1.ll
new file mode 100644 (file)
index 0000000..d2479f4
--- /dev/null
@@ -0,0 +1,10 @@
+; RUN: not llvm-as < %s >/dev/null 2> %t
+; RUN: FileCheck %s < %t
+; Test that a vector index is only used with a vector pointer.
+
+; CHECK: getelementptr index type missmatch
+
+define i32 @test(i32* %a) {
+  %w = getelementptr i32* %a, <2 x i32> <i32 5, i32 9>
+  ret i32 %w
+}
diff --git a/test/Assembler/getelementptr_vec_idx2.ll b/test/Assembler/getelementptr_vec_idx2.ll
new file mode 100644 (file)
index 0000000..8b71ce3
--- /dev/null
@@ -0,0 +1,10 @@
+; RUN: not llvm-as < %s >/dev/null 2> %t
+; RUN: FileCheck %s < %t
+; Test that a vector pointer is only used with a vector index.
+
+; CHECK: getelementptr index type missmatch
+
+define <2 x i32> @test(<2 x i32*> %a) {
+  %w = getelementptr <2 x i32*> %a, i32 2
+  ret <2 x i32> %w
+}
diff --git a/test/Assembler/getelementptr_vec_idx3.ll b/test/Assembler/getelementptr_vec_idx3.ll
new file mode 100644 (file)
index 0000000..1f6c29b
--- /dev/null
@@ -0,0 +1,10 @@
+; RUN: not llvm-as < %s >/dev/null 2> %t
+; RUN: FileCheck %s < %t
+; Test that vector indices have the same number of elements as the pointer.
+
+; CHECK: getelementptr index type missmatch
+
+define <4 x i32> @test(<4 x i32>* %a) {
+  %w = getelementptr <4 x i32>* %a, <2 x i32> <i32 5, i32 9>
+  ret i32 %w
+}
diff --git a/test/Assembler/getelementptr_vec_struct.ll b/test/Assembler/getelementptr_vec_struct.ll
new file mode 100644 (file)
index 0000000..ec66836
--- /dev/null
@@ -0,0 +1,10 @@
+; RUN: not llvm-as < %s >/dev/null 2> %t
+; RUN: FileCheck %s < %t
+; Test that a vector struct index with non-equal elements is rejected.
+
+; CHECK: invalid getelementptr indices
+
+define <2 x i32*> @test7(<2 x {i32, i32}*> %a) {
+  %w = getelementptr <2 x {i32, i32}*> %a, <2 x i32> <i32 5, i32 9>, <2 x i32> <i32 0, i32 1>
+  ret <2 x i32*> %w
+}
index fce29d2404873b6a4fb13a0a28fa729dfe6a3499..2243a77d3bc20d6d7034f6d196914e7315bd28a9 100644 (file)
@@ -391,9 +391,9 @@ define void @example13(i32** nocapture %A, i32** nocapture %B, i32* nocapture %o
   ret void
 }
 
-; Can't vectorize because of reductions.
+; Can vectorize.
 ;CHECK: @example14
-;CHECK-NOT: <4 x i32>
+;CHECK: <4 x i32>
 ;CHECK: ret void
 define void @example14(i32** nocapture %in, i32** nocapture %coeff, i32* nocapture %out) nounwind uwtable ssp {
 .preheader3: