mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
Extended syntax of vector version of getelementptr instruction.
The justification of this change is here: http://lists.cs.uiuc.edu/pipermail/llvmdev/2015-March/082989.html According to the current GEP syntax, vector GEP requires that each index must be a vector with the same number of elements. %A = getelementptr i8, <4 x i8*> %ptrs, <4 x i64> %offsets In this implementation I let each index be or vector or scalar. All vector indices must have the same number of elements. The scalar value will mean the splat vector value. (1) %A = getelementptr i8, i8* %ptr, <4 x i64> %offsets or (2) %A = getelementptr i8, <4 x i8*> %ptrs, i64 %offset In all cases the %A type is <4 x i8*> In the case (2) we add the same offset to all pointers. The case (1) covers C[B[i]] case, when we have the same base C and different offsets B[i]. The documentation is updated. http://reviews.llvm.org/D10496 llvm-svn: 241788
This commit is contained in:
parent
0248df44fb
commit
88c04dfc81
@ -6718,7 +6718,8 @@ Overview:
|
|||||||
|
|
||||||
The '``getelementptr``' instruction is used to get the address of a
|
The '``getelementptr``' instruction is used to get the address of a
|
||||||
subelement of an :ref:`aggregate <t_aggregate>` data structure. It performs
|
subelement of an :ref:`aggregate <t_aggregate>` data structure. It performs
|
||||||
address calculation only and does not access memory.
|
address calculation only and does not access memory. The instruction can also
|
||||||
|
be used to calculate a vector of such addresses.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
""""""""""
|
""""""""""
|
||||||
@ -6844,12 +6845,61 @@ Example:
|
|||||||
; yields i32*:iptr
|
; yields i32*:iptr
|
||||||
%iptr = getelementptr [10 x i32], [10 x i32]* @arr, i16 0, i16 0
|
%iptr = getelementptr [10 x i32], [10 x i32]* @arr, i16 0, i16 0
|
||||||
|
|
||||||
In cases where the pointer argument is a vector of pointers, each index
|
Vector of pointers:
|
||||||
must be a vector with the same number of elements. For example:
|
"""""""""""""""""""
|
||||||
|
|
||||||
|
The ``getelementptr`` returns a vector of pointers, instead of a single address,
|
||||||
|
when one or more of its arguments is a vector. In such cases, all vector
|
||||||
|
arguments should have the same number of elements, and every scalar argument
|
||||||
|
will be effectively broadcast into a vector during address calculation.
|
||||||
|
|
||||||
.. code-block:: llvm
|
.. code-block:: llvm
|
||||||
|
|
||||||
%A = getelementptr i8, <4 x i8*> %ptrs, <4 x i64> %offsets,
|
; All arguments are vectors:
|
||||||
|
; A[i] = ptrs[i] + offsets[i]*sizeof(i8)
|
||||||
|
%A = getelementptr i8, <4 x i8*> %ptrs, <4 x i64> %offsets
|
||||||
|
|
||||||
|
; Add the same scalar offset to each pointer of a vector:
|
||||||
|
; A[i] = ptrs[i] + offset*sizeof(i8)
|
||||||
|
%A = getelementptr i8, <4 x i8*> %ptrs, i64 %offset
|
||||||
|
|
||||||
|
; Add distinct offsets to the same pointer:
|
||||||
|
; A[i] = ptr + offsets[i]*sizeof(i8)
|
||||||
|
%A = getelementptr i8, i8* %ptr, <4 x i64> %offsets
|
||||||
|
|
||||||
|
; In all cases described above the type of the result is <4 x i8*>
|
||||||
|
|
||||||
|
The two following instructions are equivalent:
|
||||||
|
|
||||||
|
.. code-block:: llvm
|
||||||
|
|
||||||
|
getelementptr %struct.ST, <4 x %struct.ST*> %s, <4 x i64> %ind1,
|
||||||
|
<4 x i32> <i32 2, i32 2, i32 2, i32 2>,
|
||||||
|
<4 x i32> <i32 1, i32 1, i32 1, i32 1>,
|
||||||
|
<4 x i32> %ind4,
|
||||||
|
<4 x i64> <i64 13, i64 13, i64 13, i64 13>
|
||||||
|
|
||||||
|
getelementptr %struct.ST, <4 x %struct.ST*> %s, <4 x i64> %ind1,
|
||||||
|
i32 2, i32 1, <4 x i32> %ind4, i64 13
|
||||||
|
|
||||||
|
Let's look at the C code, where the vector version of ``getelementptr``
|
||||||
|
makes sense:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
// Let's assume that we vectorize the following loop:
|
||||||
|
double *A, B; int *C;
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
A[i] = B[C[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
.. code-block:: llvm
|
||||||
|
|
||||||
|
; get pointers for 8 elements from array B
|
||||||
|
%ptrs = getelementptr double, double* %B, <8 x i32> %C
|
||||||
|
; load 8 elements from array B into A
|
||||||
|
%A = call <8 x double> @llvm.masked.gather.v8f64(<8 x double*> %ptrs,
|
||||||
|
i32 8, <8 x i1> %mask, <8 x double> %passthru)
|
||||||
|
|
||||||
Conversion Operations
|
Conversion Operations
|
||||||
---------------------
|
---------------------
|
||||||
|
@ -990,10 +990,14 @@ public:
|
|||||||
Ptr->getType()->getPointerAddressSpace());
|
Ptr->getType()->getPointerAddressSpace());
|
||||||
// Vector GEP
|
// Vector GEP
|
||||||
if (Ptr->getType()->isVectorTy()) {
|
if (Ptr->getType()->isVectorTy()) {
|
||||||
unsigned NumElem = cast<VectorType>(Ptr->getType())->getNumElements();
|
unsigned NumElem = Ptr->getType()->getVectorNumElements();
|
||||||
return VectorType::get(PtrTy, NumElem);
|
return VectorType::get(PtrTy, NumElem);
|
||||||
}
|
}
|
||||||
|
for (Value *Index : IdxList)
|
||||||
|
if (Index->getType()->isVectorTy()) {
|
||||||
|
unsigned NumElem = Index->getType()->getVectorNumElements();
|
||||||
|
return VectorType::get(PtrTy, NumElem);
|
||||||
|
}
|
||||||
// Scalar GEP
|
// Scalar GEP
|
||||||
return PtrTy;
|
return PtrTy;
|
||||||
}
|
}
|
||||||
|
@ -2873,8 +2873,8 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) {
|
|||||||
if (ValTy->isVectorTy() != BaseType->isVectorTy())
|
if (ValTy->isVectorTy() != BaseType->isVectorTy())
|
||||||
return Error(ID.Loc, "getelementptr index type missmatch");
|
return Error(ID.Loc, "getelementptr index type missmatch");
|
||||||
if (ValTy->isVectorTy()) {
|
if (ValTy->isVectorTy()) {
|
||||||
unsigned ValNumEl = cast<VectorType>(ValTy)->getNumElements();
|
unsigned ValNumEl = ValTy->getVectorNumElements();
|
||||||
unsigned PtrNumEl = cast<VectorType>(BaseType)->getNumElements();
|
unsigned PtrNumEl = BaseType->getVectorNumElements();
|
||||||
if (ValNumEl != PtrNumEl)
|
if (ValNumEl != PtrNumEl)
|
||||||
return Error(
|
return Error(
|
||||||
ID.Loc,
|
ID.Loc,
|
||||||
@ -5572,6 +5572,11 @@ int LLParser::ParseGetElementPtr(Instruction *&Inst, PerFunctionState &PFS) {
|
|||||||
|
|
||||||
SmallVector<Value*, 16> Indices;
|
SmallVector<Value*, 16> Indices;
|
||||||
bool AteExtraComma = false;
|
bool AteExtraComma = false;
|
||||||
|
// GEP returns a vector of pointers if at least one of parameters is a vector.
|
||||||
|
// All vector parameters should have the same vector width.
|
||||||
|
unsigned GEPWidth = BaseType->isVectorTy() ?
|
||||||
|
BaseType->getVectorNumElements() : 0;
|
||||||
|
|
||||||
while (EatIfPresent(lltok::comma)) {
|
while (EatIfPresent(lltok::comma)) {
|
||||||
if (Lex.getKind() == lltok::MetadataVar) {
|
if (Lex.getKind() == lltok::MetadataVar) {
|
||||||
AteExtraComma = true;
|
AteExtraComma = true;
|
||||||
@ -5580,14 +5585,13 @@ int LLParser::ParseGetElementPtr(Instruction *&Inst, PerFunctionState &PFS) {
|
|||||||
if (ParseTypeAndValue(Val, EltLoc, PFS)) return true;
|
if (ParseTypeAndValue(Val, EltLoc, PFS)) return true;
|
||||||
if (!Val->getType()->getScalarType()->isIntegerTy())
|
if (!Val->getType()->getScalarType()->isIntegerTy())
|
||||||
return Error(EltLoc, "getelementptr index must be an integer");
|
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()) {
|
if (Val->getType()->isVectorTy()) {
|
||||||
unsigned ValNumEl = cast<VectorType>(Val->getType())->getNumElements();
|
unsigned ValNumEl = Val->getType()->getVectorNumElements();
|
||||||
unsigned PtrNumEl = cast<VectorType>(Ptr->getType())->getNumElements();
|
if (GEPWidth && GEPWidth != ValNumEl)
|
||||||
if (ValNumEl != PtrNumEl)
|
|
||||||
return Error(EltLoc,
|
return Error(EltLoc,
|
||||||
"getelementptr vector index has a wrong number of elements");
|
"getelementptr vector index has a wrong number of elements");
|
||||||
|
GEPWidth = ValNumEl;
|
||||||
}
|
}
|
||||||
Indices.push_back(Val);
|
Indices.push_back(Val);
|
||||||
}
|
}
|
||||||
|
@ -2787,6 +2787,16 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) {
|
|||||||
SDValue N = getValue(Op0);
|
SDValue N = getValue(Op0);
|
||||||
SDLoc dl = getCurSDLoc();
|
SDLoc dl = getCurSDLoc();
|
||||||
|
|
||||||
|
// Normalize Vector GEP - all scalar operands should be converted to the
|
||||||
|
// splat vector.
|
||||||
|
unsigned VectorWidth = I.getType()->isVectorTy() ?
|
||||||
|
cast<VectorType>(I.getType())->getVectorNumElements() : 0;
|
||||||
|
|
||||||
|
if (VectorWidth && !N.getValueType().isVector()) {
|
||||||
|
MVT VT = MVT::getVectorVT(N.getValueType().getSimpleVT(), VectorWidth);
|
||||||
|
SmallVector<SDValue, 16> Ops(VectorWidth, N);
|
||||||
|
N = DAG.getNode(ISD::BUILD_VECTOR, dl, VT, Ops);
|
||||||
|
}
|
||||||
for (GetElementPtrInst::const_op_iterator OI = I.op_begin()+1, E = I.op_end();
|
for (GetElementPtrInst::const_op_iterator OI = I.op_begin()+1, E = I.op_end();
|
||||||
OI != E; ++OI) {
|
OI != E; ++OI) {
|
||||||
const Value *Idx = *OI;
|
const Value *Idx = *OI;
|
||||||
@ -2807,12 +2817,20 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) {
|
|||||||
unsigned PtrSize = PtrTy.getSizeInBits();
|
unsigned PtrSize = PtrTy.getSizeInBits();
|
||||||
APInt ElementSize(PtrSize, DL->getTypeAllocSize(Ty));
|
APInt ElementSize(PtrSize, DL->getTypeAllocSize(Ty));
|
||||||
|
|
||||||
// If this is a constant subscript, handle it quickly.
|
// If this is a scalar constant or a splat vector of constants,
|
||||||
if (const auto *CI = dyn_cast<ConstantInt>(Idx)) {
|
// handle it quickly.
|
||||||
|
const auto *CI = dyn_cast<ConstantInt>(Idx);
|
||||||
|
if (!CI && isa<ConstantDataVector>(Idx) &&
|
||||||
|
cast<ConstantDataVector>(Idx)->getSplatValue())
|
||||||
|
CI = cast<ConstantInt>(cast<ConstantDataVector>(Idx)->getSplatValue());
|
||||||
|
|
||||||
|
if (CI) {
|
||||||
if (CI->isZero())
|
if (CI->isZero())
|
||||||
continue;
|
continue;
|
||||||
APInt Offs = ElementSize * CI->getValue().sextOrTrunc(PtrSize);
|
APInt Offs = ElementSize * CI->getValue().sextOrTrunc(PtrSize);
|
||||||
SDValue OffsVal = DAG.getConstant(Offs, dl, PtrTy);
|
SDValue OffsVal = VectorWidth ?
|
||||||
|
DAG.getConstant(Offs, dl, MVT::getVectorVT(PtrTy, VectorWidth)) :
|
||||||
|
DAG.getConstant(Offs, dl, PtrTy);
|
||||||
N = DAG.getNode(ISD::ADD, dl, N.getValueType(), N, OffsVal);
|
N = DAG.getNode(ISD::ADD, dl, N.getValueType(), N, OffsVal);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -2820,6 +2838,11 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) {
|
|||||||
// N = N + Idx * ElementSize;
|
// N = N + Idx * ElementSize;
|
||||||
SDValue IdxN = getValue(Idx);
|
SDValue IdxN = getValue(Idx);
|
||||||
|
|
||||||
|
if (!IdxN.getValueType().isVector() && VectorWidth) {
|
||||||
|
MVT VT = MVT::getVectorVT(IdxN.getValueType().getSimpleVT(), VectorWidth);
|
||||||
|
SmallVector<SDValue, 16> Ops(VectorWidth, IdxN);
|
||||||
|
IdxN = DAG.getNode(ISD::BUILD_VECTOR, dl, VT, Ops);
|
||||||
|
}
|
||||||
// If the index is smaller or larger than intptr_t, truncate or extend
|
// If the index is smaller or larger than intptr_t, truncate or extend
|
||||||
// it.
|
// it.
|
||||||
IdxN = DAG.getSExtOrTrunc(IdxN, dl, N.getValueType());
|
IdxN = DAG.getSExtOrTrunc(IdxN, dl, N.getValueType());
|
||||||
|
@ -2538,10 +2538,6 @@ void Verifier::visitGetElementPtrInst(GetElementPtrInst &GEP) {
|
|||||||
Assert(isa<PointerType>(TargetTy),
|
Assert(isa<PointerType>(TargetTy),
|
||||||
"GEP base pointer is not a vector or a vector of pointers", &GEP);
|
"GEP base pointer is not a vector or a vector of pointers", &GEP);
|
||||||
Assert(GEP.getSourceElementType()->isSized(), "GEP into unsized type!", &GEP);
|
Assert(GEP.getSourceElementType()->isSized(), "GEP into unsized type!", &GEP);
|
||||||
Assert(GEP.getPointerOperandType()->isVectorTy() ==
|
|
||||||
GEP.getType()->isVectorTy(),
|
|
||||||
"Vector GEP must return a vector value", &GEP);
|
|
||||||
|
|
||||||
SmallVector<Value*, 16> Idxs(GEP.idx_begin(), GEP.idx_end());
|
SmallVector<Value*, 16> Idxs(GEP.idx_begin(), GEP.idx_end());
|
||||||
Type *ElTy =
|
Type *ElTy =
|
||||||
GetElementPtrInst::getIndexedType(GEP.getSourceElementType(), Idxs);
|
GetElementPtrInst::getIndexedType(GEP.getSourceElementType(), Idxs);
|
||||||
@ -2551,17 +2547,20 @@ void Verifier::visitGetElementPtrInst(GetElementPtrInst &GEP) {
|
|||||||
GEP.getResultElementType() == ElTy,
|
GEP.getResultElementType() == ElTy,
|
||||||
"GEP is not of right type for indices!", &GEP, ElTy);
|
"GEP is not of right type for indices!", &GEP, ElTy);
|
||||||
|
|
||||||
if (GEP.getPointerOperandType()->isVectorTy()) {
|
if (GEP.getType()->isVectorTy()) {
|
||||||
// Additional checks for vector GEPs.
|
// Additional checks for vector GEPs.
|
||||||
unsigned GepWidth = GEP.getPointerOperandType()->getVectorNumElements();
|
unsigned GEPWidth = GEP.getType()->getVectorNumElements();
|
||||||
Assert(GepWidth == GEP.getType()->getVectorNumElements(),
|
if (GEP.getPointerOperandType()->isVectorTy())
|
||||||
"Vector GEP result width doesn't match operand's", &GEP);
|
Assert(GEPWidth == GEP.getPointerOperandType()->getVectorNumElements(),
|
||||||
|
"Vector GEP result width doesn't match operand's", &GEP);
|
||||||
for (unsigned i = 0, e = Idxs.size(); i != e; ++i) {
|
for (unsigned i = 0, e = Idxs.size(); i != e; ++i) {
|
||||||
Type *IndexTy = Idxs[i]->getType();
|
Type *IndexTy = Idxs[i]->getType();
|
||||||
Assert(IndexTy->isVectorTy(), "Vector GEP must have vector indices!",
|
if (IndexTy->isVectorTy()) {
|
||||||
&GEP);
|
unsigned IndexWidth = IndexTy->getVectorNumElements();
|
||||||
unsigned IndexWidth = IndexTy->getVectorNumElements();
|
Assert(IndexWidth == GEPWidth, "Invalid GEP index vector width", &GEP);
|
||||||
Assert(IndexWidth == GepWidth, "Invalid GEP index vector width", &GEP);
|
}
|
||||||
|
Assert(IndexTy->getScalarType()->isIntegerTy(),
|
||||||
|
"All GEP indices should be of integer type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visitInstruction(GEP);
|
visitInstruction(GEP);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
; RUN: not llvm-as < %s >/dev/null 2> %t
|
; RUN: not llvm-as < %s >/dev/null 2> %t
|
||||||
; RUN: FileCheck %s < %t
|
; RUN: FileCheck %s < %t
|
||||||
; Test that a vector index is only used with a vector pointer.
|
; Test that a vector GEP may be used with a scalar base, the result is a vector of pointers
|
||||||
|
|
||||||
; CHECK: getelementptr index type missmatch
|
; CHECK: '%w' defined with type '<2 x i32*>
|
||||||
|
|
||||||
define i32 @test(i32* %a) {
|
define i32 @test(i32* %a) {
|
||||||
%w = getelementptr i32, i32* %a, <2 x i32> <i32 5, i32 9>
|
%w = getelementptr i32, i32* %a, <2 x i32> <i32 5, i32 9>
|
||||||
|
@ -1,10 +1,24 @@
|
|||||||
; RUN: not llvm-as < %s >/dev/null 2> %t
|
; RUN: not llvm-as < %s >/dev/null 2> %t
|
||||||
; RUN: FileCheck %s < %t
|
; RUN: FileCheck %s < %t
|
||||||
; Test that a vector pointer is only used with a vector index.
|
; Test that a vector pointer may be used with a scalar index.
|
||||||
|
; Test that a vector pointer and vector index should have the same vector width
|
||||||
|
|
||||||
; CHECK: getelementptr index type missmatch
|
; This code is correct
|
||||||
|
define <2 x i32*> @test2(<2 x i32*> %a) {
|
||||||
define <2 x i32> @test(<2 x i32*> %a) {
|
|
||||||
%w = getelementptr i32, <2 x i32*> %a, i32 2
|
%w = getelementptr i32, <2 x i32*> %a, i32 2
|
||||||
|
ret <2 x i32*> %w
|
||||||
|
}
|
||||||
|
|
||||||
|
; This code is correct
|
||||||
|
define <2 x i32*> @test3(i32* %a) {
|
||||||
|
%w = getelementptr i32, i32* %a, <2 x i32> <i32 2, i32 2>
|
||||||
|
ret <2 x i32*> %w
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK: getelementptr vector index has a wrong number of elements
|
||||||
|
|
||||||
|
define <2 x i32> @test1(<2 x i32*> %a) {
|
||||||
|
%w = getelementptr i32, <2 x i32*> %a, <4 x i32><i32 2, i32 2, i32 2, i32 2>
|
||||||
ret <2 x i32> %w
|
ret <2 x i32> %w
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
; RUN: not llvm-as < %s >/dev/null 2> %t
|
; RUN: not llvm-as < %s >/dev/null 2> %t
|
||||||
; RUN: FileCheck %s < %t
|
; RUN: FileCheck %s < %t
|
||||||
; Test that vector indices have the same number of elements as the pointer.
|
; Test that a vector GEP may be used with a scalar base, the result is a vector of pointers
|
||||||
|
|
||||||
; CHECK: getelementptr index type missmatch
|
; CHECK: '%w' defined with type '<2 x <4 x i32>*>'
|
||||||
|
|
||||||
define <4 x i32> @test(<4 x i32>* %a) {
|
define <4 x i32> @test(<4 x i32>* %a) {
|
||||||
%w = getelementptr <4 x i32>, <4 x i32>* %a, <2 x i32> <i32 5, i32 9>
|
%w = getelementptr <4 x i32>, <4 x i32>* %a, <2 x i32> <i32 5, i32 9>
|
||||||
|
@ -92,3 +92,25 @@ entry:
|
|||||||
;CHECK: ret
|
;CHECK: ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
;CHECK-LABEL: AGEP7:
|
||||||
|
define <4 x i8*> @AGEP7(<4 x i8*> %param, i32 %off) nounwind {
|
||||||
|
entry:
|
||||||
|
;CHECK: vbroadcastss
|
||||||
|
;CHECK: vpadd
|
||||||
|
%A = getelementptr i8, <4 x i8*> %param, i32 %off
|
||||||
|
ret <4 x i8*> %A
|
||||||
|
;CHECK: ret
|
||||||
|
}
|
||||||
|
|
||||||
|
;CHECK-LABEL: AGEP8:
|
||||||
|
define <4 x i16*> @AGEP8(i16* %param, <4 x i32> %off) nounwind {
|
||||||
|
entry:
|
||||||
|
; Multiply offset by two (add it to itself).
|
||||||
|
;CHECK: vpadd
|
||||||
|
; add the base to the offset
|
||||||
|
;CHECK: vbroadcastss
|
||||||
|
;CHECK-NEXT: vpadd
|
||||||
|
%A = getelementptr i16, i16* %param, <4 x i32> %off
|
||||||
|
ret <4 x i16*> %A
|
||||||
|
;CHECK: ret
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user