From 1608769abeb1430dc34f31ffac0d9850f99ae36a Mon Sep 17 00:00:00 2001 From: Nadav Rotem Date: Mon, 5 Dec 2011 06:29:09 +0000 Subject: [PATCH] Add support for vectors of pointers. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@145801 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LangRef.html | 52 +++++-- include/llvm/DerivedTypes.h | 2 + include/llvm/Instructions.h | 39 +++-- include/llvm/Operator.h | 4 +- include/llvm/Target/TargetLowering.h | 15 +- include/llvm/Type.h | 4 + lib/Analysis/ConstantFolding.cpp | 3 +- lib/Analysis/InstructionSimplify.cpp | 7 +- lib/Analysis/ValueTracking.cpp | 10 +- lib/AsmParser/LLParser.cpp | 35 +++-- .../SelectionDAG/SelectionDAGBuilder.cpp | 2 +- .../InstCombine/InstCombineCalls.cpp | 2 + .../InstCombine/InstructionCombining.cpp | 9 +- lib/Transforms/Scalar/IndVarSimplify.cpp | 5 + .../Scalar/ScalarReplAggregates.cpp | 2 + lib/VMCore/Constants.cpp | 16 +- lib/VMCore/Instructions.cpp | 34 ++++- lib/VMCore/Type.cpp | 10 ++ lib/VMCore/Verifier.cpp | 72 +++++++-- test/CodeGen/X86/pointer-vector.ll | 138 ++++++++++++++++++ test/CodeGen/X86/vector-gep.ll | 77 ++++++++++ test/Feature/const_pv.ll | 8 + test/Feature/global_pv.ll | 14 ++ test/Transforms/InstCombine/vector_gep1.ll | 37 +++++ test/Transforms/InstSimplify/vector_gep.ll | 8 + unittests/VMCore/InstructionsTest.cpp | 97 ++++++++++++ 26 files changed, 631 insertions(+), 71 deletions(-) create mode 100644 test/CodeGen/X86/pointer-vector.ll create mode 100644 test/CodeGen/X86/vector-gep.ll create mode 100644 test/Feature/const_pv.ll create mode 100644 test/Feature/global_pv.ll create mode 100644 test/Transforms/InstCombine/vector_gep1.ll create mode 100644 test/Transforms/InstSimplify/vector_gep.ll diff --git a/docs/LangRef.html b/docs/LangRef.html index 2329bdb1c8b..12c140f8237 100644 --- a/docs/LangRef.html +++ b/docs/LangRef.html @@ -2189,8 +2189,8 @@ in signal handlers).

The number of elements is a constant integer value larger than 0; elementtype - may be any integer or floating point type. Vectors of size zero are not - allowed, and pointers are not allowed as the element type.

+ may be any integer or floating point type, or a pointer to these types. + Vectors of size zero are not allowed.

Examples:
@@ -2206,6 +2206,10 @@ in signal handlers).

+ + + +
<2 x i64> Vector of 2 64-bit integer values.
<4 x i64*>Vector of 4 pointers to 64-bit integer values.
@@ -5069,6 +5073,7 @@ specified by the operation argument:

   <result> = getelementptr <pty>* <ptrval>{, <ty> <idx>}*
   <result> = getelementptr inbounds <pty>* <ptrval>{, <ty> <idx>}*
+  <result> = getelementptr <ptr vector> ptrval, <vector index type> idx 
 
Overview:
@@ -5077,7 +5082,8 @@ specified by the operation argument:

It performs address calculation only and does not access memory.

Arguments:
-

The first argument is always a pointer, and forms the basis of the +

The first argument is always a pointer or a vector of pointers, + and forms the basis of the calculation. The remaining arguments are indices that indicate which of the elements of the aggregate object are indexed. The interpretation of each index is dependent on the type being indexed into. The first index always @@ -5162,7 +5168,9 @@ entry: precise signed arithmetic are not an in bounds address of that allocated object. The in bounds addresses for an allocated object are all the addresses that point into the object, plus the address one - byte past the end.

+ byte past the end. + In cases where the base is a vector of pointers the inbounds keyword + applies to each of the computations element-wise.

If the inbounds keyword is not present, the offsets are added to the base address with silently-wrapping two's complement arithmetic. If the @@ -5189,6 +5197,13 @@ entry: %iptr = getelementptr [10 x i32]* @arr, i16 0, i16 0 +

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:

+
+ %A = getelementptr <4 x i8*> %ptrs, <4 x i64> %offsets,
+
+ @@ -5561,13 +5576,16 @@ entry:
Overview:
-

The 'ptrtoint' instruction converts the pointer value to - the integer type ty2.

+

The 'ptrtoint' instruction converts the pointer or a vector of + pointers value to + the integer (or vector of integers) type ty2.

Arguments:

The 'ptrtoint' instruction takes a value to cast, which - must be a pointer value, and a type to cast it to - ty2, which must be an integer type.

+ must be a a value of type pointer or a vector of + pointers, and a type to cast it to + ty2, which must be an integer or a vector + of integers type.

Semantics:

The 'ptrtoint' instruction converts value to integer type @@ -5580,8 +5598,9 @@ entry:

Example:
-  %X = ptrtoint i32* %X to i8           ; yields truncation on 32-bit architecture
-  %Y = ptrtoint i32* %x to i64          ; yields zero extension on 32-bit architecture
+  %X = ptrtoint i32* %P to i8                         ; yields truncation on 32-bit architecture
+  %Y = ptrtoint i32* %P to i64                        ; yields zero extension on 32-bit architecture
+  %Z = ptrtoint <4 x i32*> %P to <4 x i64>; yields vector zero extension for a vector of addresses on 32-bit architecture
 
@@ -5620,6 +5639,7 @@ entry: %X = inttoptr i32 255 to i32* ; yields zero extension on 64-bit architecture %Y = inttoptr i32 255 to i32* ; yields no-op on 32-bit architecture %Z = inttoptr i64 0 to i32* ; yields truncation on 32-bit architecture + %Z = inttoptr <4 x i32> %G to <4 x i8*>; yields truncation of vector G to four pointers @@ -5654,8 +5674,9 @@ entry:

The 'bitcast' instruction converts value to type ty2. It is always a no-op cast because no bits change with this conversion. The conversion is done as if the value had been - stored to memory and read back as type ty2. Pointer types may only - be converted to other pointer types with this instruction. To convert + stored to memory and read back as type ty2. + Pointer (or vector of pointers) types may only be converted to other pointer + (or vector of pointers) types with this instruction. To convert pointers to other types, use the inttoptr or ptrtoint instructions first.

@@ -5663,7 +5684,8 @@ entry:
   %X = bitcast i8 255 to i8              ; yields i8 :-1
   %Y = bitcast i32* %x to sint*          ; yields sint*:%x
-  %Z = bitcast <2 x int> %V to i64;      ; yields i64: %V
+  %Z = bitcast <2 x int> %V to i64;        ; yields i64: %V
+  %Z = bitcast <2 x i32*> %V to <2 x i64*> ; yields <2 x i64*>
 
@@ -5694,8 +5716,8 @@ entry:
Overview:

The 'icmp' instruction returns a boolean value or a vector of - boolean values based on comparison of its two integer, integer vector, or - pointer operands.

+ boolean values based on comparison of its two integer, integer vector, + pointer, or pointer vector operands.

Arguments:

The 'icmp' instruction takes three operands. The first operand is diff --git a/include/llvm/DerivedTypes.h b/include/llvm/DerivedTypes.h index 445c3deb7ce..b9ade512cfb 100644 --- a/include/llvm/DerivedTypes.h +++ b/include/llvm/DerivedTypes.h @@ -374,6 +374,7 @@ public: /// static VectorType *getInteger(VectorType *VTy) { 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()); } @@ -408,6 +409,7 @@ public: unsigned getNumElements() const { return NumElements; } /// @brief Return the number of bits in the Vector type. + /// Returns zero when the vector is a vector of pointers. unsigned getBitWidth() const { return NumElements * getElementType()->getPrimitiveSizeInBits(); } diff --git a/include/llvm/Instructions.h b/include/llvm/Instructions.h index 3faab35bf68..e87950eb393 100644 --- a/include/llvm/Instructions.h +++ b/include/llvm/Instructions.h @@ -776,6 +776,10 @@ public: static Type *getIndexedType(Type *Ptr, ArrayRef IdxList); static Type *getIndexedType(Type *Ptr, ArrayRef IdxList); + /// getIndexedType - Returns the address space used by the GEP pointer. + /// + static unsigned getAddressSpace(Value *Ptr); + inline op_iterator idx_begin() { return op_begin()+1; } inline const_op_iterator idx_begin() const { return op_begin()+1; } inline op_iterator idx_end() { return op_end(); } @@ -788,7 +792,7 @@ public: return getOperand(0); } static unsigned getPointerOperandIndex() { - return 0U; // get index for modifying correct operand + return 0U; // get index for modifying correct operand. } unsigned getPointerAddressSpace() const { @@ -797,10 +801,25 @@ public: /// getPointerOperandType - Method to return the pointer operand as a /// PointerType. - PointerType *getPointerOperandType() const { - return reinterpret_cast(getPointerOperand()->getType()); + Type *getPointerOperandType() const { + return getPointerOperand()->getType(); } + /// GetGEPReturnType - Returns the pointer type returned by the GEP + /// instruction, which may be a vector of pointers. + static Type *getGEPReturnType(Value *Ptr, ArrayRef IdxList) { + Type *PtrTy = PointerType::get(checkGEPType( + getIndexedType(Ptr->getType(), IdxList)), + getAddressSpace(Ptr)); + // Vector GEP + if (Ptr->getType()->isVectorTy()) { + unsigned NumElem = cast(Ptr->getType())->getNumElements(); + return VectorType::get(PtrTy, NumElem); + } + + // Scalar GEP + return PtrTy; + } unsigned getNumIndices() const { // Note: always non-negative return getNumOperands() - 1; @@ -847,10 +866,7 @@ GetElementPtrInst::GetElementPtrInst(Value *Ptr, unsigned Values, const Twine &NameStr, Instruction *InsertBefore) - : Instruction(PointerType::get(checkGEPType( - getIndexedType(Ptr->getType(), IdxList)), - cast(Ptr->getType()) - ->getAddressSpace()), + : Instruction(getGEPReturnType(Ptr, IdxList), GetElementPtr, OperandTraits::op_end(this) - Values, Values, InsertBefore) { @@ -861,10 +877,7 @@ GetElementPtrInst::GetElementPtrInst(Value *Ptr, unsigned Values, const Twine &NameStr, BasicBlock *InsertAtEnd) - : Instruction(PointerType::get(checkGEPType( - getIndexedType(Ptr->getType(), IdxList)), - cast(Ptr->getType()) - ->getAddressSpace()), + : Instruction(getGEPReturnType(Ptr, IdxList), GetElementPtr, OperandTraits::op_end(this) - Values, Values, InsertAtEnd) { @@ -905,7 +918,7 @@ public: "Both operands to ICmp instruction are not of the same type!"); // Check that the operands are the right type assert((getOperand(0)->getType()->isIntOrIntVectorTy() || - getOperand(0)->getType()->isPointerTy()) && + getOperand(0)->getType()->getScalarType()->isPointerTy()) && "Invalid operand types for ICmp instruction"); } @@ -945,7 +958,7 @@ public: "Both operands to ICmp instruction are not of the same type!"); // Check that the operands are the right type assert((getOperand(0)->getType()->isIntOrIntVectorTy() || - getOperand(0)->getType()->isPointerTy()) && + getOperand(0)->getType()->getScalarType()->isPointerTy()) && "Invalid operand types for ICmp instruction"); } diff --git a/include/llvm/Operator.h b/include/llvm/Operator.h index 48a5796383b..abd6a1939d7 100644 --- a/include/llvm/Operator.h +++ b/include/llvm/Operator.h @@ -261,8 +261,8 @@ public: /// getPointerOperandType - Method to return the pointer operand as a /// PointerType. - PointerType *getPointerOperandType() const { - return reinterpret_cast(getPointerOperand()->getType()); + Type *getPointerOperandType() const { + return getPointerOperand()->getType(); } unsigned getNumIndices() const { // Note: always non-negative diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 3fe3a38b2a0..67179fc8f47 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -520,8 +520,19 @@ public: /// AllowUnknown is true, this will return MVT::Other for types with no EVT /// counterpart (e.g. structs), otherwise it will assert. EVT getValueType(Type *Ty, bool AllowUnknown = false) const { - EVT VT = EVT::getEVT(Ty, AllowUnknown); - return VT == MVT::iPTR ? PointerTy : VT; + // Lower scalar pointers to native pointer types. + if (Ty->isPointerTy()) return PointerTy; + + if (Ty->isVectorTy()) { + VectorType *VTy = cast(Ty); + Type *Elm = VTy->getElementType(); + // Lower vectors of pointers to native pointer types. + if (Elm->isPointerTy()) + Elm = EVT(PointerTy).getTypeForEVT(Ty->getContext()); + return EVT::getVectorVT(Ty->getContext(), EVT::getEVT(Elm, false), + VTy->getNumElements()); + } + return EVT::getEVT(Ty, AllowUnknown); } /// getByValTypeAlignment - Return the desired alignment for ByVal aggregate diff --git a/include/llvm/Type.h b/include/llvm/Type.h index 43b7dc57888..a571b4dbe50 100644 --- a/include/llvm/Type.h +++ b/include/llvm/Type.h @@ -273,6 +273,10 @@ public: /// otherwise return 'this'. Type *getScalarType(); + /// getNumElements - If this is a vector type, return the number of elements, + /// otherwise return zero. + unsigned getNumElements(); + //===--------------------------------------------------------------------===// // Type Iteration support. // diff --git a/lib/Analysis/ConstantFolding.cpp b/lib/Analysis/ConstantFolding.cpp index d12476885e4..7e98b218884 100644 --- a/lib/Analysis/ConstantFolding.cpp +++ b/lib/Analysis/ConstantFolding.cpp @@ -580,7 +580,8 @@ static Constant *SymbolicallyEvaluateGEP(ArrayRef Ops, Type *ResultTy, const TargetData *TD, const TargetLibraryInfo *TLI) { Constant *Ptr = Ops[0]; - if (!TD || !cast(Ptr->getType())->getElementType()->isSized()) + if (!TD || !cast(Ptr->getType())->getElementType()->isSized() || + !Ptr->getType()->isPointerTy()) return 0; Type *IntPtrTy = TD->getIntPtrType(Ptr->getContext()); diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp index b52f6435453..f1cfd6ceadd 100644 --- a/lib/Analysis/InstructionSimplify.cpp +++ b/lib/Analysis/InstructionSimplify.cpp @@ -1764,7 +1764,7 @@ static Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS, // also a case of comparing two zero-extended values. if (RExt == CI && MaxRecurse) if (Value *V = SimplifyICmpInst(ICmpInst::getUnsignedPredicate(Pred), - SrcOp, Trunc, TD, TLI, DT, MaxRecurse-1)) + SrcOp, Trunc, TD, TLI, DT, MaxRecurse-1)) return V; // Otherwise the upper bits of LHS are zero while RHS has a non-zero bit @@ -2359,7 +2359,10 @@ Value *llvm::SimplifySelectInst(Value *CondVal, Value *TrueVal, Value *FalseVal, Value *llvm::SimplifyGEPInst(ArrayRef Ops, const TargetData *TD, const DominatorTree *) { // The type of the GEP pointer operand. - PointerType *PtrTy = cast(Ops[0]->getType()); + PointerType *PtrTy = dyn_cast(Ops[0]->getType()); + // The GEP pointer operand is not a pointer, it's a vector of pointers. + if (!PtrTy) + return 0; // getelementptr P -> P. if (Ops.size() == 1) diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index 58adc26a1d7..0d016e21f26 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -63,13 +63,14 @@ void llvm::ComputeMaskedBits(Value *V, const APInt &Mask, assert(V && "No Value?"); assert(Depth <= MaxDepth && "Limit Search Depth"); unsigned BitWidth = Mask.getBitWidth(); - assert((V->getType()->isIntOrIntVectorTy() || V->getType()->isPointerTy()) - && "Not integer or pointer type!"); + assert((V->getType()->isIntOrIntVectorTy() || + V->getType()->getScalarType()->isPointerTy()) && + "Not integer or pointer type!"); assert((!TD || TD->getTypeSizeInBits(V->getType()->getScalarType()) == BitWidth) && (!V->getType()->isIntOrIntVectorTy() || V->getType()->getScalarSizeInBits() == BitWidth) && - KnownZero.getBitWidth() == BitWidth && + KnownZero.getBitWidth() == BitWidth && KnownOne.getBitWidth() == BitWidth && "V, Mask, KnownOne and KnownZero should have same BitWidth"); @@ -1557,7 +1558,8 @@ Value *llvm::FindInsertedValue(Value *V, ArrayRef idx_range, Value *llvm::GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, const TargetData &TD) { Operator *PtrOp = dyn_cast(Ptr); - if (PtrOp == 0) return Ptr; + if (PtrOp == 0 || Ptr->getType()->isVectorTy()) + return Ptr; // Just look through bitcasts. if (PtrOp->getOpcode() == Instruction::BitCast) diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 212c9fb38d5..1ef69105d64 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -1607,7 +1607,8 @@ 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 or integer"); + return Error(TypeLoc, + "vector element type must be fp, integer or a pointer to these types"); Result = VectorType::get(EltTy, unsigned(Size)); } else { if (!ArrayType::isValidElementType(EltTy)) @@ -1966,9 +1967,10 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) { return Error(ID.Loc, "constant vector must not be empty"); if (!Elts[0]->getType()->isIntegerTy() && - !Elts[0]->getType()->isFloatingPointTy()) + !Elts[0]->getType()->isFloatingPointTy() && + !Elts[0]->getType()->isPointerTy()) return Error(FirstEltLoc, - "vector elements must have integer or floating point type"); + "vector elements must have integer, pointer or floating point type"); // Verify that all the vector elements have the same type. for (unsigned i = 1, e = Elts.size(); i != e; ++i) @@ -2160,7 +2162,7 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) { } else { assert(Opc == Instruction::ICmp && "Unexpected opcode for CmpInst!"); if (!Val0->getType()->isIntOrIntVectorTy() && - !Val0->getType()->isPointerTy()) + !Val0->getType()->getScalarType()->isPointerTy()) return Error(ID.Loc, "icmp requires pointer or integer operands"); ID.ConstantVal = ConstantExpr::getICmp(Pred, Val0, Val1); } @@ -2294,7 +2296,8 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) { return true; if (Opc == Instruction::GetElementPtr) { - if (Elts.size() == 0 || !Elts[0]->getType()->isPointerTy()) + if (Elts.size() == 0 || + !Elts[0]->getType()->getScalarType()->isPointerTy()) return Error(ID.Loc, "getelementptr requires pointer operand"); ArrayRef Indices(Elts.begin() + 1, Elts.end()); @@ -3329,7 +3332,7 @@ bool LLParser::ParseCompare(Instruction *&Inst, PerFunctionState &PFS, } else { assert(Opc == Instruction::ICmp && "Unknown opcode for CmpInst!"); if (!LHS->getType()->isIntOrIntVectorTy() && - !LHS->getType()->isPointerTy()) + !LHS->getType()->getScalarType()->isPointerTy()) return Error(Loc, "icmp requires integer operands"); Inst = new ICmpInst(CmpInst::Predicate(Pred), LHS, RHS); } @@ -3877,13 +3880,15 @@ int LLParser::ParseFence(Instruction *&Inst, PerFunctionState &PFS) { /// ParseGetElementPtr /// ::= 'getelementptr' 'inbounds'? TypeAndValue (',' TypeAndValue)* int LLParser::ParseGetElementPtr(Instruction *&Inst, PerFunctionState &PFS) { - Value *Ptr, *Val; LocTy Loc, EltLoc; + Value *Ptr = 0; + Value *Val = 0; + LocTy Loc, EltLoc; bool InBounds = EatIfPresent(lltok::kw_inbounds); if (ParseTypeAndValue(Ptr, Loc, PFS)) return true; - if (!Ptr->getType()->isPointerTy()) + if (!Ptr->getType()->getScalarType()->isPointerTy()) return Error(Loc, "base of getelementptr must be a pointer"); SmallVector Indices; @@ -3894,11 +3899,23 @@ int LLParser::ParseGetElementPtr(Instruction *&Inst, PerFunctionState &PFS) { break; } if (ParseTypeAndValue(Val, EltLoc, PFS)) return true; - if (!Val->getType()->isIntegerTy()) + if (!Val->getType()->getScalarType()->isIntegerTy()) return Error(EltLoc, "getelementptr index must be an integer"); + if (Val->getType()->isVectorTy() != Ptr->getType()->isVectorTy()) + return Error(EltLoc, "getelementptr index type missmatch"); + if (Val->getType()->isVectorTy()) { + unsigned ValNumEl = cast(Val->getType())->getNumElements(); + unsigned PtrNumEl = cast(Ptr->getType())->getNumElements(); + if (ValNumEl != PtrNumEl) + return Error(EltLoc, + "getelementptr vector index has a wrong number of elements"); + } 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); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index a77401e3595..ac24ce5868e 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -3099,7 +3099,7 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) { unsigned Amt = ElementSize.logBase2(); IdxN = DAG.getNode(ISD::SHL, getCurDebugLoc(), N.getValueType(), IdxN, - DAG.getConstant(Amt, TLI.getPointerTy())); + DAG.getConstant(Amt, IdxN.getValueType())); } else { SDValue Scale = DAG.getConstant(ElementSize, TLI.getPointerTy()); IdxN = DAG.getNode(ISD::MUL, getCurDebugLoc(), diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp index 81dad7e022e..27c7c54a9c8 100644 --- a/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -265,6 +265,8 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { // Get the current byte offset into the thing. Use the original // operand in case we're looking through a bitcast. SmallVector Ops(GEP->idx_begin(), GEP->idx_end()); + if (!GEP->getPointerOperandType()->isPointerTy()) + return 0; Offset = TD->getIndexedOffset(GEP->getPointerOperandType(), Ops); Op1 = GEP->getPointerOperand()->stripPointerCasts(); diff --git a/lib/Transforms/InstCombine/InstructionCombining.cpp b/lib/Transforms/InstCombine/InstructionCombining.cpp index 50794deba3f..af065cd886e 100644 --- a/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -831,7 +831,8 @@ Instruction *InstCombiner::visitGetElementPtrInst(GetElementPtrInst &GEP) { MadeChange = true; } - if ((*I)->getType() != IntPtrTy) { + Type *IndexTy = (*I)->getType(); + if (IndexTy != IntPtrTy && !IndexTy->isVectorTy()) { // If we are using a wider index than needed for this platform, shrink // it to what we need. If narrower, sign-extend it to what we need. // This explicit cast can make subsequent optimizations more obvious. @@ -914,7 +915,11 @@ Instruction *InstCombiner::visitGetElementPtrInst(GetElementPtrInst &GEP) { // Handle gep(bitcast x) and gep(gep x, 0, 0, 0). Value *StrippedPtr = PtrOp->stripPointerCasts(); - PointerType *StrippedPtrTy =cast(StrippedPtr->getType()); + PointerType *StrippedPtrTy = dyn_cast(StrippedPtr->getType()); + // We do not handle pointer-vector geps here + if (!StrippedPtr) + return 0; + if (StrippedPtr != PtrOp && StrippedPtrTy->getAddressSpace() == GEP.getPointerAddressSpace()) { diff --git a/lib/Transforms/Scalar/IndVarSimplify.cpp b/lib/Transforms/Scalar/IndVarSimplify.cpp index ea083e36ca4..1176cc9a04b 100644 --- a/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -178,6 +178,11 @@ bool IndVarSimplify::isValidRewrite(Value *FromVal, Value *ToVal) { // base of a recurrence. This handles the case in which SCEV expansion // converts a pointer type recurrence into a nonrecurrent pointer base // indexed by an integer recurrence. + + // If the GEP base pointer is a vector of pointers, abort. + if (!FromPtr->getType()->isPointerTy() || !ToPtr->getType()->isPointerTy()) + return false; + const SCEV *FromBase = SE->getPointerBase(SE->getSCEV(FromPtr)); const SCEV *ToBase = SE->getPointerBase(SE->getSCEV(ToPtr)); if (FromBase == ToBase) diff --git a/lib/Transforms/Scalar/ScalarReplAggregates.cpp b/lib/Transforms/Scalar/ScalarReplAggregates.cpp index 4b14efcd063..bc70c51cc01 100644 --- a/lib/Transforms/Scalar/ScalarReplAggregates.cpp +++ b/lib/Transforms/Scalar/ScalarReplAggregates.cpp @@ -453,6 +453,8 @@ bool ConvertToScalarInfo::CanConvertToScalar(Value *V, uint64_t Offset) { // Compute the offset that this GEP adds to the pointer. SmallVector Indices(GEP->op_begin()+1, GEP->op_end()); + if (!GEP->getPointerOperandType()->isPointerTy()) + return false; uint64_t GEPOffset = TD.getIndexedOffset(GEP->getPointerOperandType(), Indices); // See if all uses can be converted. diff --git a/lib/VMCore/Constants.cpp b/lib/VMCore/Constants.cpp index cd94da13534..a1489123ca7 100644 --- a/lib/VMCore/Constants.cpp +++ b/lib/VMCore/Constants.cpp @@ -1398,14 +1398,22 @@ Constant *ConstantExpr::getFPToSI(Constant *C, Type *Ty) { } Constant *ConstantExpr::getPtrToInt(Constant *C, Type *DstTy) { - assert(C->getType()->isPointerTy() && "PtrToInt source must be pointer"); - assert(DstTy->isIntegerTy() && "PtrToInt destination must be integral"); + assert(C->getType()->getScalarType()->isPointerTy() && + "PtrToInt source must be pointer or pointer vector"); + assert(DstTy->getScalarType()->isIntegerTy() && + "PtrToInt destination must be integer or integer vector"); + assert(C->getType()->getNumElements() == DstTy->getNumElements() && + "Invalid cast between a different number of vector elements"); return getFoldedCast(Instruction::PtrToInt, C, DstTy); } Constant *ConstantExpr::getIntToPtr(Constant *C, Type *DstTy) { - assert(C->getType()->isIntegerTy() && "IntToPtr source must be integral"); - assert(DstTy->isPointerTy() && "IntToPtr destination must be a pointer"); + assert(C->getType()->getScalarType()->isIntegerTy() && + "IntToPtr source must be integer or integer vector"); + assert(DstTy->getScalarType()->isPointerTy() && + "IntToPtr destination must be a pointer or pointer vector"); + assert(C->getType()->getNumElements() == DstTy->getNumElements() && + "Invalid cast between a different number of vector elements"); return getFoldedCast(Instruction::IntToPtr, C, DstTy); } diff --git a/lib/VMCore/Instructions.cpp b/lib/VMCore/Instructions.cpp index 6fa904e4e44..4784f0c6e0f 100644 --- a/lib/VMCore/Instructions.cpp +++ b/lib/VMCore/Instructions.cpp @@ -1359,6 +1359,15 @@ GetElementPtrInst::GetElementPtrInst(const GetElementPtrInst &GEPI) /// template static Type *getIndexedTypeInternal(Type *Ptr, ArrayRef IdxList) { + if (Ptr->isVectorTy()) { + assert(IdxList.size() == 1 && + "GEP with vector pointers must have a single index"); + PointerType *PTy = dyn_cast( + cast(Ptr)->getElementType()); + assert(PTy && "Gep with invalid vector pointer found"); + return PTy->getElementType(); + } + PointerType *PTy = dyn_cast(Ptr); if (!PTy) return 0; // Type isn't a pointer type! Type *Agg = PTy->getElementType(); @@ -1366,7 +1375,7 @@ static Type *getIndexedTypeInternal(Type *Ptr, ArrayRef IdxList) { // Handle the special case of the empty set index set, which is always valid. if (IdxList.empty()) return Agg; - + // If there is at least one index, the top level type must be sized, otherwise // it cannot be 'stepped over'. if (!Agg->isSized()) @@ -1396,6 +1405,19 @@ Type *GetElementPtrInst::getIndexedType(Type *Ptr, ArrayRef IdxList) { return getIndexedTypeInternal(Ptr, IdxList); } +unsigned GetElementPtrInst::getAddressSpace(Value *Ptr) { + Type *Ty = Ptr->getType(); + + if (VectorType *VTy = dyn_cast(Ty)) + Ty = VTy->getElementType(); + + if (PointerType *PTy = dyn_cast(Ty)) + return PTy->getAddressSpace(); + + assert(false && "Invalid GEP pointer type"); + return 0; +} + /// hasAllZeroIndices - Return true if all of the indices of this GEP are /// zeros. If so, the result pointer and the first operand have the same /// value, just potentially different types. @@ -2654,9 +2676,15 @@ CastInst::castIsValid(Instruction::CastOps op, Value *S, Type *DstTy) { return SrcTy->isFPOrFPVectorTy() && DstTy->isIntOrIntVectorTy() && SrcLength == DstLength; case Instruction::PtrToInt: - return SrcTy->isPointerTy() && DstTy->isIntegerTy(); + if (SrcTy->getNumElements() != DstTy->getNumElements()) + return false; + return SrcTy->getScalarType()->isPointerTy() && + DstTy->getScalarType()->isIntegerTy(); case Instruction::IntToPtr: - return SrcTy->isIntegerTy() && DstTy->isPointerTy(); + if (SrcTy->getNumElements() != DstTy->getNumElements()) + return false; + return SrcTy->getScalarType()->isIntegerTy() && + DstTy->getScalarType()->isPointerTy(); case Instruction::BitCast: // BitCast implies a no-op cast of type only. No bits change. // However, you can't cast pointers to anything but pointers. diff --git a/lib/VMCore/Type.cpp b/lib/VMCore/Type.cpp index 10184bc6f0e..469defdb85d 100644 --- a/lib/VMCore/Type.cpp +++ b/lib/VMCore/Type.cpp @@ -46,6 +46,14 @@ Type *Type::getScalarType() { return this; } +/// getNumElements - If this is a vector type, return the number of elements, +/// otherwise return zero. +unsigned Type::getNumElements() { + if (VectorType *VTy = dyn_cast(this)) + return VTy->getNumElements(); + return 0; +} + /// isIntegerTy - Return true if this is an IntegerType of the specified width. bool Type::isIntegerTy(unsigned Bitwidth) const { return isIntegerTy() && cast(this)->getBitWidth() == Bitwidth; @@ -664,6 +672,8 @@ VectorType *VectorType::get(Type *elementType, unsigned NumElements) { } bool VectorType::isValidElementType(Type *ElemTy) { + if (PointerType *PTy = dyn_cast(ElemTy)) + ElemTy = PTy->getElementType(); return ElemTy->isIntegerTy() || ElemTy->isFloatingPointTy(); } diff --git a/lib/VMCore/Verifier.cpp b/lib/VMCore/Verifier.cpp index 9564b7d71f6..f74d762be94 100644 --- a/lib/VMCore/Verifier.cpp +++ b/lib/VMCore/Verifier.cpp @@ -1035,8 +1035,19 @@ void Verifier::visitPtrToIntInst(PtrToIntInst &I) { Type *SrcTy = I.getOperand(0)->getType(); Type *DestTy = I.getType(); - Assert1(SrcTy->isPointerTy(), "PtrToInt source must be pointer", &I); - Assert1(DestTy->isIntegerTy(), "PtrToInt result must be integral", &I); + Assert1(SrcTy->getScalarType()->isPointerTy(), + "PtrToInt source must be pointer", &I); + Assert1(DestTy->getScalarType()->isIntegerTy(), + "PtrToInt result must be integral", &I); + Assert1(SrcTy->isVectorTy() == DestTy->isVectorTy(), + "PtrToInt type mismatch", &I); + + if (SrcTy->isVectorTy()) { + VectorType *VSrc = dyn_cast(SrcTy); + VectorType *VDest = dyn_cast(DestTy); + Assert1(VSrc->getNumElements() == VDest->getNumElements(), + "PtrToInt Vector width mismatch", &I); + } visitInstruction(I); } @@ -1046,9 +1057,18 @@ void Verifier::visitIntToPtrInst(IntToPtrInst &I) { Type *SrcTy = I.getOperand(0)->getType(); Type *DestTy = I.getType(); - Assert1(SrcTy->isIntegerTy(), "IntToPtr source must be an integral", &I); - Assert1(DestTy->isPointerTy(), "IntToPtr result must be a pointer",&I); - + Assert1(SrcTy->getScalarType()->isIntegerTy(), + "IntToPtr source must be an integral", &I); + Assert1(DestTy->getScalarType()->isPointerTy(), + "IntToPtr result must be a pointer",&I); + Assert1(SrcTy->isVectorTy() == DestTy->isVectorTy(), + "IntToPtr type mismatch", &I); + if (SrcTy->isVectorTy()) { + VectorType *VSrc = dyn_cast(SrcTy); + VectorType *VDest = dyn_cast(DestTy); + Assert1(VSrc->getNumElements() == VDest->getNumElements(), + "IntToPtr Vector width mismatch", &I); + } visitInstruction(I); } @@ -1245,7 +1265,7 @@ void Verifier::visitICmpInst(ICmpInst &IC) { Assert1(Op0Ty == Op1Ty, "Both operands to ICmp instruction are not of the same type!", &IC); // Check that the operands are the right type - Assert1(Op0Ty->isIntOrIntVectorTy() || Op0Ty->isPointerTy(), + Assert1(Op0Ty->isIntOrIntVectorTy() || Op0Ty->getScalarType()->isPointerTy(), "Invalid operand types for ICmp instruction", &IC); // Check that the predicate is valid. Assert1(IC.getPredicate() >= CmpInst::FIRST_ICMP_PREDICATE && @@ -1295,17 +1315,43 @@ void Verifier::visitShuffleVectorInst(ShuffleVectorInst &SV) { } void Verifier::visitGetElementPtrInst(GetElementPtrInst &GEP) { - Assert1(cast(GEP.getOperand(0)->getType()) - ->getElementType()->isSized(), + Type *TargetTy = GEP.getPointerOperandType(); + if (VectorType *VTy = dyn_cast(TargetTy)) + TargetTy = VTy->getElementType(); + + Assert1(dyn_cast(TargetTy), + "GEP base pointer is not a vector or a vector of pointers", &GEP); + Assert1(cast(TargetTy)->getElementType()->isSized(), "GEP into unsized type!", &GEP); - + SmallVector Idxs(GEP.idx_begin(), GEP.idx_end()); Type *ElTy = - GetElementPtrInst::getIndexedType(GEP.getOperand(0)->getType(), Idxs); + GetElementPtrInst::getIndexedType(GEP.getPointerOperandType(), Idxs); Assert1(ElTy, "Invalid indices for GEP pointer type!", &GEP); - Assert2(GEP.getType()->isPointerTy() && - cast(GEP.getType())->getElementType() == ElTy, - "GEP is not of right type for indices!", &GEP, ElTy); + + if (GEP.getPointerOperandType()->isPointerTy()) { + // Validate GEPs with scalar indices. + Assert2(GEP.getType()->isPointerTy() && + cast(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(GEP.getType())->getElementType(); + Assert1(ElemPtr->isPointerTy(), + "Vector GEP pointer operand is not a pointer!", &GEP); + unsigned IndexWidth = cast(IndexTy)->getNumElements(); + unsigned GepWidth = cast(GEP.getType())->getNumElements(); + Assert1(IndexWidth == GepWidth, "Invalid GEP index vector width", &GEP); + Assert1(ElTy == cast(ElemPtr)->getElementType(), + "Vector GEP type does not match pointer type!", &GEP); + } visitInstruction(GEP); } diff --git a/test/CodeGen/X86/pointer-vector.ll b/test/CodeGen/X86/pointer-vector.ll new file mode 100644 index 00000000000..9c1c5213126 --- /dev/null +++ b/test/CodeGen/X86/pointer-vector.ll @@ -0,0 +1,138 @@ +; RUN: llc < %s -march=x86 -mcpu=corei7 | FileCheck %s +; RUN: opt -instsimplify %s -disable-output + +;CHECK: SHUFF0 +define <8 x i32*> @SHUFF0(<4 x i32*> %ptrv) nounwind { +entry: + %G = shufflevector <4 x i32*> %ptrv, <4 x i32*> %ptrv, <8 x i32> +;CHECK: pshufd + ret <8 x i32*> %G +;CHECK: ret +} + +;CHECK: SHUFF1 +define <4 x i32*> @SHUFF1(<4 x i32*> %ptrv) nounwind { +entry: + %G = shufflevector <4 x i32*> %ptrv, <4 x i32*> %ptrv, <4 x i32> +;CHECK: pshufd + ret <4 x i32*> %G +;CHECK: ret +} + +;CHECK: SHUFF3 +define <4 x i8*> @SHUFF3(<4 x i8*> %ptrv) nounwind { +entry: + %G = shufflevector <4 x i8*> %ptrv, <4 x i8*> undef, <4 x i32> +;CHECK: pshufd + ret <4 x i8*> %G +;CHECK: ret +} + +;CHECK: LOAD0 +define <4 x i8*> @LOAD0(<4 x i8*>* %p) nounwind { +entry: + %G = load <4 x i8*>* %p +;CHECK: movaps + ret <4 x i8*> %G +;CHECK: ret +} + +;CHECK: LOAD1 +define <4 x i8*> @LOAD1(<4 x i8*>* %p) nounwind { +entry: + %G = load <4 x i8*>* %p +;CHECK: movdqa +;CHECK: pshufd +;CHECK: movdqa + %T = shufflevector <4 x i8*> %G, <4 x i8*> %G, <4 x i32> + store <4 x i8*> %T, <4 x i8*>* %p + ret <4 x i8*> %G +;CHECK: ret +} + +;CHECK: LOAD2 +define <4 x i8*> @LOAD2(<4 x i8*>* %p) nounwind { +entry: + %I = alloca <4 x i8*> +;CHECK: sub + %G = load <4 x i8*>* %p +;CHECK: movaps + store <4 x i8*> %G, <4 x i8*>* %I +;CHECK: movaps + %Z = load <4 x i8*>* %I + ret <4 x i8*> %Z +;CHECK: add +;CHECK: ret +} + +;CHECK: INT2PTR0 +define <4 x i32> @INT2PTR0(<4 x i8*>* %p) nounwind { +entry: + %G = load <4 x i8*>* %p +;CHECK: movl +;CHECK: movaps + %K = ptrtoint <4 x i8*> %G to <4 x i32> +;CHECK: ret + ret <4 x i32> %K +} + +;CHECK: INT2PTR1 +define <4 x i32*> @INT2PTR1(<4 x i8>* %p) nounwind { +entry: + %G = load <4 x i8>* %p +;CHECK: movl +;CHECK: movd +;CHECK: pshufb +;CHECK: pand + %K = inttoptr <4 x i8> %G to <4 x i32*> +;CHECK: ret + ret <4 x i32*> %K +} + +;CHECK: BITCAST0 +define <4 x i32*> @BITCAST0(<4 x i8*>* %p) nounwind { +entry: + %G = load <4 x i8*>* %p +;CHECK: movl + %T = bitcast <4 x i8*> %G to <4 x i32*> +;CHECK: movaps +;CHECK: ret + ret <4 x i32*> %T +} + +;CHECK: BITCAST1 +define <2 x i32*> @BITCAST1(<2 x i8*>* %p) nounwind { +entry: + %G = load <2 x i8*>* %p +;CHECK: movl +;CHECK: movd +;CHECK: pinsrd + %T = bitcast <2 x i8*> %G to <2 x i32*> +;CHECK: ret + ret <2 x i32*> %T +} + +;CHECK: ICMP0 +define <4 x i32> @ICMP0(<4 x i8*>* %p0, <4 x i8*>* %p1) nounwind { +entry: + %g0 = load <4 x i8*>* %p0 + %g1 = load <4 x i8*>* %p1 + %k = icmp sgt <4 x i8*> %g0, %g1 + ;CHECK: pcmpgtd + %j = select <4 x i1> %k, <4 x i32> , <4 x i32> + ret <4 x i32> %j + ;CHECK: ret +} + +;CHECK: ICMP1 +define <4 x i32> @ICMP1(<4 x i8*>* %p0, <4 x i8*>* %p1) nounwind { +entry: + %g0 = load <4 x i8*>* %p0 + %g1 = load <4 x i8*>* %p1 + %k = icmp eq <4 x i8*> %g0, %g1 + ;CHECK: pcmpeqd + %j = select <4 x i1> %k, <4 x i32> , <4 x i32> + ret <4 x i32> %j + ;CHECK: ret +} + diff --git a/test/CodeGen/X86/vector-gep.ll b/test/CodeGen/X86/vector-gep.ll new file mode 100644 index 00000000000..d032eda88be --- /dev/null +++ b/test/CodeGen/X86/vector-gep.ll @@ -0,0 +1,77 @@ +; RUN: llc < %s -march=x86 -mcpu=corei7-avx | FileCheck %s +; RUN: opt -instsimplify %s -disable-output + +;CHECK: AGEP0 +define <4 x i32*> @AGEP0(i32* %ptr) nounwind { +entry: + %vecinit.i = insertelement <4 x i32*> undef, i32* %ptr, i32 0 + %vecinit2.i = insertelement <4 x i32*> %vecinit.i, i32* %ptr, i32 1 + %vecinit4.i = insertelement <4 x i32*> %vecinit2.i, i32* %ptr, i32 2 + %vecinit6.i = insertelement <4 x i32*> %vecinit4.i, i32* %ptr, i32 3 +;CHECK: pslld +;CHECK: padd + %A2 = getelementptr <4 x i32*> %vecinit6.i, <4 x i32> +;CHECK: pslld +;CHECK: padd + %A3 = getelementptr <4 x i32*> %A2, <4 x i32> + ret <4 x i32*> %A3 +;CHECK: ret +} + +;CHECK: AGEP1 +define i32 @AGEP1(<4 x i32*> %param) nounwind { +entry: +;CHECK: pslld +;CHECK: padd + %A2 = getelementptr <4 x i32*> %param, <4 x i32> + %k = extractelement <4 x i32*> %A2, i32 3 + %v = load i32* %k + ret i32 %v +;CHECK: ret +} + +;CHECK: AGEP2 +define i32 @AGEP2(<4 x i32*> %param, <4 x i32> %off) nounwind { +entry: +;CHECK: pslld +;CHECK: padd + %A2 = getelementptr <4 x i32*> %param, <4 x i32> %off + %k = extractelement <4 x i32*> %A2, i32 3 + %v = load i32* %k + ret i32 %v +;CHECK: ret +} + +;CHECK: AGEP3 +define <4 x i32*> @AGEP3(<4 x i32*> %param, <4 x i32> %off) nounwind { +entry: +;CHECK: pslld +;CHECK: padd + %A2 = getelementptr <4 x i32*> %param, <4 x i32> %off + %v = alloca i32 + %k = insertelement <4 x i32*> %A2, i32* %v, i32 3 + ret <4 x i32*> %k +;CHECK: ret +} + +;CHECK: AGEP4 +define <4 x i8*> @AGEP4(<4 x i8*> %param, <4 x i32> %off) nounwind { +entry: +;CHECK: pslld +;CHECK: padd + %A = getelementptr <4 x i8*> %param, <4 x i32> %off + ret <4 x i8*> %A +;CHECK: ret +} + +;CHECK: AGEP5 +define <4 x i8*> @AGEP5(<4 x i8*> %param, <4 x i8> %off) nounwind { +entry: +;CHECK: pslld +;CHECK: padd + %A = getelementptr <4 x i8*> %param, <4 x i8> %off + ret <4 x i8*> %A +;CHECK: ret +} + + diff --git a/test/Feature/const_pv.ll b/test/Feature/const_pv.ll new file mode 100644 index 00000000000..6fd6abdccf0 --- /dev/null +++ b/test/Feature/const_pv.ll @@ -0,0 +1,8 @@ +; RUN: llvm-as %s -disable-output +@G = constant <3 x i64> ptrtoint (<3 x i8*> to <3 x i64>) + +@G1 = global i8 zeroinitializer +@g = constant <2 x i8*> getelementptr (<2 x i8*> , <2 x i32> ) + +@t = constant <2 x i1> icmp ((<2 x i32> ptrtoint (<2 x i8*> zeroinitializer to <2 x i32>), <2 x i32> zeroinitializer ) + diff --git a/test/Feature/global_pv.ll b/test/Feature/global_pv.ll new file mode 100644 index 00000000000..d257ec077ab --- /dev/null +++ b/test/Feature/global_pv.ll @@ -0,0 +1,14 @@ +; RUN: opt -instcombine -S -o - %s | llvm-as +; RUN: opt -instcombine -globalopt -S -o - %s | llvm-as +@G1 = global i32 zeroinitializer +@G2 = global i32 zeroinitializer +@g = global <2 x i32*> zeroinitializer +%0 = type { i32, void ()* } +@llvm.global_ctors = appending global [1 x %0] [%0 { i32 65535, void ()* @test }] +define internal void @test() { + %A = insertelement <2 x i32*> undef, i32* @G1, i32 0 + %B = insertelement <2 x i32*> %A, i32* @G2, i32 1 + store <2 x i32*> %B, <2 x i32*>* @g + ret void +} + diff --git a/test/Transforms/InstCombine/vector_gep1.ll b/test/Transforms/InstCombine/vector_gep1.ll new file mode 100644 index 00000000000..65236229956 --- /dev/null +++ b/test/Transforms/InstCombine/vector_gep1.ll @@ -0,0 +1,37 @@ +; RUN: opt -instcombine %s -disable-output +; RUN: opt -instsimplify %s -disable-output +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@G1 = global i8 zeroinitializer + +define <2 x i1> @test(<2 x i8*> %a, <2 x i8*> %b) { + %A = icmp eq <2 x i8*> %a, %b + ret <2 x i1> %A +} + +define <2 x i1> @test2(<2 x i8*> %a) { + %A = inttoptr <2 x i32> to <2 x i8*> + %B = icmp ult <2 x i8*> %A, zeroinitializer + ret <2 x i1> %B +} + +define <2 x i1> @test3(<2 x i8*> %a) { + %g = getelementptr <2 x i8*> %a, <2 x i32> + %B = icmp ult <2 x i8*> %g, zeroinitializer + ret <2 x i1> %B +} + +define <1 x i1> @test4(<1 x i8*> %a) { + %g = getelementptr <1 x i8*> %a, <1 x i32> + %B = icmp ult <1 x i8*> %g, zeroinitializer + ret <1 x i1> %B +} + +define <2 x i1> @test5(<2 x i8*> %a) { + %w = getelementptr <2 x i8*> %a, <2 x i32> zeroinitializer + %e = getelementptr <2 x i8*> %w, <2 x i32> + %g = getelementptr <2 x i8*> %e, <2 x i32> + %B = icmp ult <2 x i8*> %g, zeroinitializer + ret <2 x i1> %B +} diff --git a/test/Transforms/InstSimplify/vector_gep.ll b/test/Transforms/InstSimplify/vector_gep.ll new file mode 100644 index 00000000000..f65260e00f5 --- /dev/null +++ b/test/Transforms/InstSimplify/vector_gep.ll @@ -0,0 +1,8 @@ +;RUN: opt -instsimplify %s -disable-output +declare void @helper(<2 x i8*>) +define void @test(<2 x i8*> %a) { + %A = getelementptr <2 x i8*> %a, <2 x i32> + call void @helper(<2 x i8*> %A) + ret void +} + diff --git a/unittests/VMCore/InstructionsTest.cpp b/unittests/VMCore/InstructionsTest.cpp index f0197bb671a..218a9a08c43 100644 --- a/unittests/VMCore/InstructionsTest.cpp +++ b/unittests/VMCore/InstructionsTest.cpp @@ -13,6 +13,8 @@ #include "llvm/DerivedTypes.h" #include "llvm/LLVMContext.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/Target/TargetData.h" #include "gtest/gtest.h" namespace llvm { @@ -129,5 +131,100 @@ TEST(InstructionsTest, CastInst) { EXPECT_EQ(CastInst::SExt, CastInst::getCastOpcode(c8, true, V8x64Ty, true)); } + + +TEST(InstructionsTest, VectorGep) { + LLVMContext &C(getGlobalContext()); + + // Type Definitions + PointerType *Ptri8Ty = PointerType::get(IntegerType::get(C, 8), 0); + PointerType *Ptri32Ty = PointerType::get(IntegerType::get(C, 8), 0); + + VectorType *V2xi8PTy = VectorType::get(Ptri8Ty, 2); + VectorType *V2xi32PTy = VectorType::get(Ptri32Ty, 2); + + // Test different aspects of the vector-of-pointers type + // and GEPs which use this type. + ConstantInt *Ci32a = ConstantInt::get(C, APInt(32, 1492)); + ConstantInt *Ci32b = ConstantInt::get(C, APInt(32, 1948)); + std::vector ConstVa(2, Ci32a); + std::vector ConstVb(2, Ci32b); + Constant *C2xi32a = ConstantVector::get(ConstVa); + Constant *C2xi32b = ConstantVector::get(ConstVb); + + CastInst *PtrVecA = new IntToPtrInst(C2xi32a, V2xi32PTy); + CastInst *PtrVecB = new IntToPtrInst(C2xi32b, V2xi32PTy); + + ICmpInst *ICmp0 = new ICmpInst(ICmpInst::ICMP_SGT, PtrVecA, PtrVecB); + ICmpInst *ICmp1 = new ICmpInst(ICmpInst::ICMP_ULT, PtrVecA, PtrVecB); + EXPECT_NE(ICmp0, ICmp1); // suppress warning. + + GetElementPtrInst *Gep0 = GetElementPtrInst::Create(PtrVecA, C2xi32a); + GetElementPtrInst *Gep1 = GetElementPtrInst::Create(PtrVecA, C2xi32b); + GetElementPtrInst *Gep2 = GetElementPtrInst::Create(PtrVecB, C2xi32a); + GetElementPtrInst *Gep3 = GetElementPtrInst::Create(PtrVecB, C2xi32b); + + CastInst *BTC0 = new BitCastInst(Gep0, V2xi8PTy); + CastInst *BTC1 = new BitCastInst(Gep1, V2xi8PTy); + CastInst *BTC2 = new BitCastInst(Gep2, V2xi8PTy); + CastInst *BTC3 = new BitCastInst(Gep3, V2xi8PTy); + + Value *S0 = BTC0->stripPointerCasts(); + Value *S1 = BTC1->stripPointerCasts(); + Value *S2 = BTC2->stripPointerCasts(); + Value *S3 = BTC3->stripPointerCasts(); + + EXPECT_NE(S0, Gep0); + EXPECT_NE(S1, Gep1); + EXPECT_NE(S2, Gep2); + EXPECT_NE(S3, Gep3); + + int64_t Offset; + TargetData TD("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3" + "2:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80" + ":128:128-n8:16:32:64-S128"); + // Make sure we don't crash + GetPointerBaseWithConstantOffset(Gep0, Offset, TD); + GetPointerBaseWithConstantOffset(Gep1, Offset, TD); + GetPointerBaseWithConstantOffset(Gep2, Offset, TD); + GetPointerBaseWithConstantOffset(Gep3, Offset, TD); + + // Gep of Geps + GetElementPtrInst *GepII0 = GetElementPtrInst::Create(Gep0, C2xi32b); + GetElementPtrInst *GepII1 = GetElementPtrInst::Create(Gep1, C2xi32a); + GetElementPtrInst *GepII2 = GetElementPtrInst::Create(Gep2, C2xi32b); + GetElementPtrInst *GepII3 = GetElementPtrInst::Create(Gep3, C2xi32a); + + EXPECT_EQ(GepII0->getNumIndices(), 1u); + EXPECT_EQ(GepII1->getNumIndices(), 1u); + EXPECT_EQ(GepII2->getNumIndices(), 1u); + EXPECT_EQ(GepII3->getNumIndices(), 1u); + + EXPECT_FALSE(GepII0->hasAllZeroIndices()); + EXPECT_FALSE(GepII1->hasAllZeroIndices()); + EXPECT_FALSE(GepII2->hasAllZeroIndices()); + EXPECT_FALSE(GepII3->hasAllZeroIndices()); + + delete GepII0; + delete GepII1; + delete GepII2; + delete GepII3; + + delete BTC0; + delete BTC1; + delete BTC2; + delete BTC3; + + delete Gep0; + delete Gep1; + delete Gep2; + delete Gep3; + + delete ICmp0; + delete ICmp1; + delete PtrVecA; + delete PtrVecB; +} + } // end anonymous namespace } // end namespace llvm -- 2.34.1