Skip to content

Commit fe088cd

Browse files
authored
Support for llvm.vector.reduce.* intrinsics (#2198)
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.
1 parent 1aae8db commit fe088cd

File tree

16 files changed

+8412
-0
lines changed

16 files changed

+8412
-0
lines changed

lib/SPIRV/SPIRVWriter.cpp

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4023,6 +4023,122 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
40234023
transValue(II->getArgOperand(0), BB),
40244024
transValue(II->getArgOperand(1), BB), BB);
40254025
}
4026+
case Intrinsic::vector_reduce_add:
4027+
case Intrinsic::vector_reduce_mul:
4028+
case Intrinsic::vector_reduce_and:
4029+
case Intrinsic::vector_reduce_or:
4030+
case Intrinsic::vector_reduce_xor: {
4031+
Op Op;
4032+
if (IID == Intrinsic::vector_reduce_add) {
4033+
Op = OpIAdd;
4034+
} else if (IID == Intrinsic::vector_reduce_mul) {
4035+
Op = OpIMul;
4036+
} else if (IID == Intrinsic::vector_reduce_and) {
4037+
Op = OpBitwiseAnd;
4038+
} else if (IID == Intrinsic::vector_reduce_or) {
4039+
Op = OpBitwiseOr;
4040+
} else {
4041+
Op = OpBitwiseXor;
4042+
}
4043+
VectorType *VecTy = cast<VectorType>(II->getArgOperand(0)->getType());
4044+
SPIRVValue *VecSVal = transValue(II->getArgOperand(0), BB);
4045+
SPIRVTypeInt *ResultSType =
4046+
BM->addIntegerType(VecTy->getElementType()->getIntegerBitWidth());
4047+
SPIRVTypeInt *I32STy = BM->addIntegerType(32);
4048+
unsigned VecSize = VecTy->getElementCount().getFixedValue();
4049+
SmallVector<SPIRVValue *, 16> Extracts(VecSize);
4050+
for (unsigned Idx = 0; Idx < VecSize; ++Idx) {
4051+
Extracts[Idx] = BM->addVectorExtractDynamicInst(
4052+
VecSVal, BM->addIntegerConstant(I32STy, Idx), BB);
4053+
}
4054+
unsigned Counter = VecSize >> 1;
4055+
while (Counter != 0) {
4056+
for (unsigned Idx = 0; Idx < Counter; ++Idx) {
4057+
Extracts[Idx] = BM->addBinaryInst(Op, ResultSType, Extracts[Idx << 1],
4058+
Extracts[(Idx << 1) + 1], BB);
4059+
}
4060+
Counter >>= 1;
4061+
}
4062+
if ((VecSize & 1) != 0) {
4063+
Extracts[0] = BM->addBinaryInst(Op, ResultSType, Extracts[0],
4064+
Extracts[VecSize - 1], BB);
4065+
}
4066+
return Extracts[0];
4067+
}
4068+
case Intrinsic::vector_reduce_fadd:
4069+
case Intrinsic::vector_reduce_fmul: {
4070+
Op Op = IID == Intrinsic::vector_reduce_fadd ? OpFAdd : OpFMul;
4071+
VectorType *VecTy = cast<VectorType>(II->getArgOperand(1)->getType());
4072+
SPIRVValue *VecSVal = transValue(II->getArgOperand(1), BB);
4073+
SPIRVValue *StartingSVal = transValue(II->getArgOperand(0), BB);
4074+
SPIRVTypeInt *I32STy = BM->addIntegerType(32);
4075+
unsigned VecSize = VecTy->getElementCount().getFixedValue();
4076+
SmallVector<SPIRVValue *, 16> Extracts(VecSize);
4077+
for (unsigned Idx = 0; Idx < VecSize; ++Idx) {
4078+
Extracts[Idx] = BM->addVectorExtractDynamicInst(
4079+
VecSVal, BM->addIntegerConstant(I32STy, Idx), BB);
4080+
}
4081+
SPIRVValue *V = BM->addBinaryInst(Op, StartingSVal->getType(), StartingSVal,
4082+
Extracts[0], BB);
4083+
for (unsigned Idx = 1; Idx < VecSize; ++Idx) {
4084+
V = BM->addBinaryInst(Op, StartingSVal->getType(), V, Extracts[Idx], BB);
4085+
}
4086+
return V;
4087+
}
4088+
case Intrinsic::vector_reduce_smax:
4089+
case Intrinsic::vector_reduce_smin:
4090+
case Intrinsic::vector_reduce_umax:
4091+
case Intrinsic::vector_reduce_umin:
4092+
case Intrinsic::vector_reduce_fmax:
4093+
case Intrinsic::vector_reduce_fmin:
4094+
case Intrinsic::vector_reduce_fmaximum:
4095+
case Intrinsic::vector_reduce_fminimum: {
4096+
Op Op;
4097+
if (IID == Intrinsic::vector_reduce_smax) {
4098+
Op = OpSGreaterThan;
4099+
} else if (IID == Intrinsic::vector_reduce_smin) {
4100+
Op = OpSLessThan;
4101+
} else if (IID == Intrinsic::vector_reduce_umax) {
4102+
Op = OpUGreaterThan;
4103+
} else if (IID == Intrinsic::vector_reduce_umin) {
4104+
Op = OpULessThan;
4105+
} else if (IID == Intrinsic::vector_reduce_fmax) {
4106+
Op = OpFOrdGreaterThan;
4107+
} else if (IID == Intrinsic::vector_reduce_fmin) {
4108+
Op = OpFOrdLessThan;
4109+
} else if (IID == Intrinsic::vector_reduce_fmaximum) {
4110+
Op = OpFUnordGreaterThan;
4111+
} else {
4112+
Op = OpFUnordLessThan;
4113+
}
4114+
VectorType *VecTy = cast<VectorType>(II->getArgOperand(0)->getType());
4115+
SPIRVValue *VecSVal = transValue(II->getArgOperand(0), BB);
4116+
SPIRVType *BoolSTy = transType(Type::getInt1Ty(II->getContext()));
4117+
SPIRVTypeInt *I32STy = BM->addIntegerType(32);
4118+
unsigned VecSize = VecTy->getElementCount().getFixedValue();
4119+
SmallVector<SPIRVValue *, 16> Extracts(VecSize);
4120+
for (unsigned Idx = 0; Idx < VecSize; ++Idx) {
4121+
Extracts[Idx] = BM->addVectorExtractDynamicInst(
4122+
VecSVal, BM->addIntegerConstant(I32STy, Idx), BB);
4123+
}
4124+
unsigned Counter = VecSize >> 1;
4125+
while (Counter != 0) {
4126+
for (unsigned Idx = 0; Idx < Counter; ++Idx) {
4127+
SPIRVValue *Cond = BM->addBinaryInst(Op, BoolSTy, Extracts[Idx << 1],
4128+
Extracts[(Idx << 1) + 1], BB);
4129+
Extracts[Idx] = BM->addSelectInst(Cond, Extracts[Idx << 1],
4130+
Extracts[(Idx << 1) + 1], BB);
4131+
}
4132+
Counter >>= 1;
4133+
}
4134+
if ((VecSize & 1) != 0) {
4135+
SPIRVValue *Cond = BM->addBinaryInst(Op, BoolSTy, Extracts[0],
4136+
Extracts[VecSize - 1], BB);
4137+
Extracts[0] =
4138+
BM->addSelectInst(Cond, Extracts[0], Extracts[VecSize - 1], BB);
4139+
}
4140+
return Extracts[0];
4141+
}
40264142
case Intrinsic::memset: {
40274143
// Generally there is no direct mapping of memset to SPIR-V. But it turns
40284144
// out that memset is emitted by Clang for initialization in default

0 commit comments

Comments
 (0)