1
0
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:
Elena Demikhovsky 2015-07-09 07:42:48 +00:00
parent 0248df44fb
commit 88c04dfc81
9 changed files with 152 additions and 36 deletions

View File

@ -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
--------------------- ---------------------

View File

@ -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;
} }

View File

@ -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);
} }

View File

@ -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());

View File

@ -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);

View File

@ -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>

View File

@ -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
} }

View File

@ -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>

View File

@ -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
}