Skip to content

Commit

Permalink
Support for llvm.vector.reduce.* intrinsics (#2198)
Browse files Browse the repository at this point in the history
A set of llvm.vector.reduce.* intrinsics doesn't have straight forward
operation equivalent on the SPIRV side. The easiest solution to this
problem is to use scalar operation on each pair of vector elements
and repeat until there is only one value.
  • Loading branch information
bwlodarcz authored Nov 14, 2023
1 parent 1aae8db commit fe088cd
Show file tree
Hide file tree
Showing 16 changed files with 8,412 additions and 0 deletions.
116 changes: 116 additions & 0 deletions lib/SPIRV/SPIRVWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4023,6 +4023,122 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
transValue(II->getArgOperand(0), BB),
transValue(II->getArgOperand(1), BB), BB);
}
case Intrinsic::vector_reduce_add:
case Intrinsic::vector_reduce_mul:
case Intrinsic::vector_reduce_and:
case Intrinsic::vector_reduce_or:
case Intrinsic::vector_reduce_xor: {
Op Op;
if (IID == Intrinsic::vector_reduce_add) {
Op = OpIAdd;
} else if (IID == Intrinsic::vector_reduce_mul) {
Op = OpIMul;
} else if (IID == Intrinsic::vector_reduce_and) {
Op = OpBitwiseAnd;
} else if (IID == Intrinsic::vector_reduce_or) {
Op = OpBitwiseOr;
} else {
Op = OpBitwiseXor;
}
VectorType *VecTy = cast<VectorType>(II->getArgOperand(0)->getType());
SPIRVValue *VecSVal = transValue(II->getArgOperand(0), BB);
SPIRVTypeInt *ResultSType =
BM->addIntegerType(VecTy->getElementType()->getIntegerBitWidth());
SPIRVTypeInt *I32STy = BM->addIntegerType(32);
unsigned VecSize = VecTy->getElementCount().getFixedValue();
SmallVector<SPIRVValue *, 16> Extracts(VecSize);
for (unsigned Idx = 0; Idx < VecSize; ++Idx) {
Extracts[Idx] = BM->addVectorExtractDynamicInst(
VecSVal, BM->addIntegerConstant(I32STy, Idx), BB);
}
unsigned Counter = VecSize >> 1;
while (Counter != 0) {
for (unsigned Idx = 0; Idx < Counter; ++Idx) {
Extracts[Idx] = BM->addBinaryInst(Op, ResultSType, Extracts[Idx << 1],
Extracts[(Idx << 1) + 1], BB);
}
Counter >>= 1;
}
if ((VecSize & 1) != 0) {
Extracts[0] = BM->addBinaryInst(Op, ResultSType, Extracts[0],
Extracts[VecSize - 1], BB);
}
return Extracts[0];
}
case Intrinsic::vector_reduce_fadd:
case Intrinsic::vector_reduce_fmul: {
Op Op = IID == Intrinsic::vector_reduce_fadd ? OpFAdd : OpFMul;
VectorType *VecTy = cast<VectorType>(II->getArgOperand(1)->getType());
SPIRVValue *VecSVal = transValue(II->getArgOperand(1), BB);
SPIRVValue *StartingSVal = transValue(II->getArgOperand(0), BB);
SPIRVTypeInt *I32STy = BM->addIntegerType(32);
unsigned VecSize = VecTy->getElementCount().getFixedValue();
SmallVector<SPIRVValue *, 16> Extracts(VecSize);
for (unsigned Idx = 0; Idx < VecSize; ++Idx) {
Extracts[Idx] = BM->addVectorExtractDynamicInst(
VecSVal, BM->addIntegerConstant(I32STy, Idx), BB);
}
SPIRVValue *V = BM->addBinaryInst(Op, StartingSVal->getType(), StartingSVal,
Extracts[0], BB);
for (unsigned Idx = 1; Idx < VecSize; ++Idx) {
V = BM->addBinaryInst(Op, StartingSVal->getType(), V, Extracts[Idx], BB);
}
return V;
}
case Intrinsic::vector_reduce_smax:
case Intrinsic::vector_reduce_smin:
case Intrinsic::vector_reduce_umax:
case Intrinsic::vector_reduce_umin:
case Intrinsic::vector_reduce_fmax:
case Intrinsic::vector_reduce_fmin:
case Intrinsic::vector_reduce_fmaximum:
case Intrinsic::vector_reduce_fminimum: {
Op Op;
if (IID == Intrinsic::vector_reduce_smax) {
Op = OpSGreaterThan;
} else if (IID == Intrinsic::vector_reduce_smin) {
Op = OpSLessThan;
} else if (IID == Intrinsic::vector_reduce_umax) {
Op = OpUGreaterThan;
} else if (IID == Intrinsic::vector_reduce_umin) {
Op = OpULessThan;
} else if (IID == Intrinsic::vector_reduce_fmax) {
Op = OpFOrdGreaterThan;
} else if (IID == Intrinsic::vector_reduce_fmin) {
Op = OpFOrdLessThan;
} else if (IID == Intrinsic::vector_reduce_fmaximum) {
Op = OpFUnordGreaterThan;
} else {
Op = OpFUnordLessThan;
}
VectorType *VecTy = cast<VectorType>(II->getArgOperand(0)->getType());
SPIRVValue *VecSVal = transValue(II->getArgOperand(0), BB);
SPIRVType *BoolSTy = transType(Type::getInt1Ty(II->getContext()));
SPIRVTypeInt *I32STy = BM->addIntegerType(32);
unsigned VecSize = VecTy->getElementCount().getFixedValue();
SmallVector<SPIRVValue *, 16> Extracts(VecSize);
for (unsigned Idx = 0; Idx < VecSize; ++Idx) {
Extracts[Idx] = BM->addVectorExtractDynamicInst(
VecSVal, BM->addIntegerConstant(I32STy, Idx), BB);
}
unsigned Counter = VecSize >> 1;
while (Counter != 0) {
for (unsigned Idx = 0; Idx < Counter; ++Idx) {
SPIRVValue *Cond = BM->addBinaryInst(Op, BoolSTy, Extracts[Idx << 1],
Extracts[(Idx << 1) + 1], BB);
Extracts[Idx] = BM->addSelectInst(Cond, Extracts[Idx << 1],
Extracts[(Idx << 1) + 1], BB);
}
Counter >>= 1;
}
if ((VecSize & 1) != 0) {
SPIRVValue *Cond = BM->addBinaryInst(Op, BoolSTy, Extracts[0],
Extracts[VecSize - 1], BB);
Extracts[0] =
BM->addSelectInst(Cond, Extracts[0], Extracts[VecSize - 1], BB);
}
return Extracts[0];
}
case Intrinsic::memset: {
// Generally there is no direct mapping of memset to SPIR-V. But it turns
// out that memset is emitted by Clang for initialization in default
Expand Down
Loading

0 comments on commit fe088cd

Please sign in to comment.