xref: /freebsd-src/contrib/llvm-project/llvm/lib/IR/VectorBuilder.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //===- VectorBuilder.cpp - Builder for VP Intrinsics ----------------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This file implements the VectorBuilder class, which is used as a convenient
1081ad6265SDimitry Andric // way to create VP intrinsics as if they were LLVM instructions with a
1181ad6265SDimitry Andric // consistent and simplified interface.
1281ad6265SDimitry Andric //
1381ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1481ad6265SDimitry Andric 
1581ad6265SDimitry Andric #include <llvm/ADT/SmallVector.h>
1681ad6265SDimitry Andric #include <llvm/IR/FPEnv.h>
1781ad6265SDimitry Andric #include <llvm/IR/Instructions.h>
1881ad6265SDimitry Andric #include <llvm/IR/IntrinsicInst.h>
1981ad6265SDimitry Andric #include <llvm/IR/Intrinsics.h>
2081ad6265SDimitry Andric #include <llvm/IR/VectorBuilder.h>
2181ad6265SDimitry Andric 
2281ad6265SDimitry Andric namespace llvm {
2381ad6265SDimitry Andric 
2481ad6265SDimitry Andric void VectorBuilder::handleError(const char *ErrorMsg) const {
2581ad6265SDimitry Andric   if (ErrorHandling == Behavior::SilentlyReturnNone)
2681ad6265SDimitry Andric     return;
2781ad6265SDimitry Andric   report_fatal_error(ErrorMsg);
2881ad6265SDimitry Andric }
2981ad6265SDimitry Andric 
3081ad6265SDimitry Andric Module &VectorBuilder::getModule() const {
3181ad6265SDimitry Andric   return *Builder.GetInsertBlock()->getModule();
3281ad6265SDimitry Andric }
3381ad6265SDimitry Andric 
3481ad6265SDimitry Andric Value *VectorBuilder::getAllTrueMask() {
3506c3fb27SDimitry Andric   return Builder.getAllOnesMask(StaticVectorLength);
3681ad6265SDimitry Andric }
3781ad6265SDimitry Andric 
3881ad6265SDimitry Andric Value &VectorBuilder::requestMask() {
3981ad6265SDimitry Andric   if (Mask)
4081ad6265SDimitry Andric     return *Mask;
4181ad6265SDimitry Andric 
4281ad6265SDimitry Andric   return *getAllTrueMask();
4381ad6265SDimitry Andric }
4481ad6265SDimitry Andric 
4581ad6265SDimitry Andric Value &VectorBuilder::requestEVL() {
4681ad6265SDimitry Andric   if (ExplicitVectorLength)
4781ad6265SDimitry Andric     return *ExplicitVectorLength;
4881ad6265SDimitry Andric 
4981ad6265SDimitry Andric   assert(!StaticVectorLength.isScalable() && "TODO vscale lowering");
5081ad6265SDimitry Andric   auto *IntTy = Builder.getInt32Ty();
5181ad6265SDimitry Andric   return *ConstantInt::get(IntTy, StaticVectorLength.getFixedValue());
5281ad6265SDimitry Andric }
5381ad6265SDimitry Andric 
5481ad6265SDimitry Andric Value *VectorBuilder::createVectorInstruction(unsigned Opcode, Type *ReturnTy,
5581ad6265SDimitry Andric                                               ArrayRef<Value *> InstOpArray,
5681ad6265SDimitry Andric                                               const Twine &Name) {
5781ad6265SDimitry Andric   auto VPID = VPIntrinsic::getForOpcode(Opcode);
5881ad6265SDimitry Andric   if (VPID == Intrinsic::not_intrinsic)
5981ad6265SDimitry Andric     return returnWithError<Value *>("No VPIntrinsic for this opcode");
60*0fca6ea1SDimitry Andric   return createVectorInstructionImpl(VPID, ReturnTy, InstOpArray, Name);
61*0fca6ea1SDimitry Andric }
6281ad6265SDimitry Andric 
63*0fca6ea1SDimitry Andric Value *VectorBuilder::createSimpleTargetReduction(RecurKind Kind, Type *ValTy,
64*0fca6ea1SDimitry Andric                                                   ArrayRef<Value *> InstOpArray,
65*0fca6ea1SDimitry Andric                                                   const Twine &Name) {
66*0fca6ea1SDimitry Andric   Intrinsic::ID VPID;
67*0fca6ea1SDimitry Andric   switch (Kind) {
68*0fca6ea1SDimitry Andric   case RecurKind::Add:
69*0fca6ea1SDimitry Andric     VPID = Intrinsic::vp_reduce_add;
70*0fca6ea1SDimitry Andric     break;
71*0fca6ea1SDimitry Andric   case RecurKind::Mul:
72*0fca6ea1SDimitry Andric     VPID = Intrinsic::vp_reduce_mul;
73*0fca6ea1SDimitry Andric     break;
74*0fca6ea1SDimitry Andric   case RecurKind::And:
75*0fca6ea1SDimitry Andric     VPID = Intrinsic::vp_reduce_and;
76*0fca6ea1SDimitry Andric     break;
77*0fca6ea1SDimitry Andric   case RecurKind::Or:
78*0fca6ea1SDimitry Andric     VPID = Intrinsic::vp_reduce_or;
79*0fca6ea1SDimitry Andric     break;
80*0fca6ea1SDimitry Andric   case RecurKind::Xor:
81*0fca6ea1SDimitry Andric     VPID = Intrinsic::vp_reduce_xor;
82*0fca6ea1SDimitry Andric     break;
83*0fca6ea1SDimitry Andric   case RecurKind::FMulAdd:
84*0fca6ea1SDimitry Andric   case RecurKind::FAdd:
85*0fca6ea1SDimitry Andric     VPID = Intrinsic::vp_reduce_fadd;
86*0fca6ea1SDimitry Andric     break;
87*0fca6ea1SDimitry Andric   case RecurKind::FMul:
88*0fca6ea1SDimitry Andric     VPID = Intrinsic::vp_reduce_fmul;
89*0fca6ea1SDimitry Andric     break;
90*0fca6ea1SDimitry Andric   case RecurKind::SMax:
91*0fca6ea1SDimitry Andric     VPID = Intrinsic::vp_reduce_smax;
92*0fca6ea1SDimitry Andric     break;
93*0fca6ea1SDimitry Andric   case RecurKind::SMin:
94*0fca6ea1SDimitry Andric     VPID = Intrinsic::vp_reduce_smin;
95*0fca6ea1SDimitry Andric     break;
96*0fca6ea1SDimitry Andric   case RecurKind::UMax:
97*0fca6ea1SDimitry Andric     VPID = Intrinsic::vp_reduce_umax;
98*0fca6ea1SDimitry Andric     break;
99*0fca6ea1SDimitry Andric   case RecurKind::UMin:
100*0fca6ea1SDimitry Andric     VPID = Intrinsic::vp_reduce_umin;
101*0fca6ea1SDimitry Andric     break;
102*0fca6ea1SDimitry Andric   case RecurKind::FMax:
103*0fca6ea1SDimitry Andric     VPID = Intrinsic::vp_reduce_fmax;
104*0fca6ea1SDimitry Andric     break;
105*0fca6ea1SDimitry Andric   case RecurKind::FMin:
106*0fca6ea1SDimitry Andric     VPID = Intrinsic::vp_reduce_fmin;
107*0fca6ea1SDimitry Andric     break;
108*0fca6ea1SDimitry Andric   case RecurKind::FMaximum:
109*0fca6ea1SDimitry Andric     VPID = Intrinsic::vp_reduce_fmaximum;
110*0fca6ea1SDimitry Andric     break;
111*0fca6ea1SDimitry Andric   case RecurKind::FMinimum:
112*0fca6ea1SDimitry Andric     VPID = Intrinsic::vp_reduce_fminimum;
113*0fca6ea1SDimitry Andric     break;
114*0fca6ea1SDimitry Andric   default:
115*0fca6ea1SDimitry Andric     llvm_unreachable("No VPIntrinsic for this reduction");
116*0fca6ea1SDimitry Andric   }
117*0fca6ea1SDimitry Andric   return createVectorInstructionImpl(VPID, ValTy, InstOpArray, Name);
118*0fca6ea1SDimitry Andric }
119*0fca6ea1SDimitry Andric 
120*0fca6ea1SDimitry Andric Value *VectorBuilder::createVectorInstructionImpl(Intrinsic::ID VPID,
121*0fca6ea1SDimitry Andric                                                   Type *ReturnTy,
122*0fca6ea1SDimitry Andric                                                   ArrayRef<Value *> InstOpArray,
123*0fca6ea1SDimitry Andric                                                   const Twine &Name) {
12481ad6265SDimitry Andric   auto MaskPosOpt = VPIntrinsic::getMaskParamPos(VPID);
12581ad6265SDimitry Andric   auto VLenPosOpt = VPIntrinsic::getVectorLengthParamPos(VPID);
12681ad6265SDimitry Andric   size_t NumInstParams = InstOpArray.size();
12781ad6265SDimitry Andric   size_t NumVPParams =
12881ad6265SDimitry Andric       NumInstParams + MaskPosOpt.has_value() + VLenPosOpt.has_value();
12981ad6265SDimitry Andric 
13081ad6265SDimitry Andric   SmallVector<Value *, 6> IntrinParams;
13181ad6265SDimitry Andric 
13281ad6265SDimitry Andric   // Whether the mask and vlen parameter are at the end of the parameter list.
13381ad6265SDimitry Andric   bool TrailingMaskAndVLen =
13481ad6265SDimitry Andric       std::min<size_t>(MaskPosOpt.value_or(NumInstParams),
13581ad6265SDimitry Andric                        VLenPosOpt.value_or(NumInstParams)) >= NumInstParams;
13681ad6265SDimitry Andric 
13781ad6265SDimitry Andric   if (TrailingMaskAndVLen) {
13881ad6265SDimitry Andric     // Fast path for trailing mask, vector length.
13981ad6265SDimitry Andric     IntrinParams.append(InstOpArray.begin(), InstOpArray.end());
14081ad6265SDimitry Andric     IntrinParams.resize(NumVPParams);
14181ad6265SDimitry Andric   } else {
14281ad6265SDimitry Andric     IntrinParams.resize(NumVPParams);
14381ad6265SDimitry Andric     // Insert mask and evl operands in between the instruction operands.
14481ad6265SDimitry Andric     for (size_t VPParamIdx = 0, ParamIdx = 0; VPParamIdx < NumVPParams;
14581ad6265SDimitry Andric          ++VPParamIdx) {
14681ad6265SDimitry Andric       if ((MaskPosOpt && MaskPosOpt.value_or(NumVPParams) == VPParamIdx) ||
14781ad6265SDimitry Andric           (VLenPosOpt && VLenPosOpt.value_or(NumVPParams) == VPParamIdx))
14881ad6265SDimitry Andric         continue;
14981ad6265SDimitry Andric       assert(ParamIdx < NumInstParams);
15081ad6265SDimitry Andric       IntrinParams[VPParamIdx] = InstOpArray[ParamIdx++];
15181ad6265SDimitry Andric     }
15281ad6265SDimitry Andric   }
15381ad6265SDimitry Andric 
15481ad6265SDimitry Andric   if (MaskPosOpt)
15581ad6265SDimitry Andric     IntrinParams[*MaskPosOpt] = &requestMask();
15681ad6265SDimitry Andric   if (VLenPosOpt)
15781ad6265SDimitry Andric     IntrinParams[*VLenPosOpt] = &requestEVL();
15881ad6265SDimitry Andric 
15981ad6265SDimitry Andric   auto *VPDecl = VPIntrinsic::getDeclarationForParams(&getModule(), VPID,
16081ad6265SDimitry Andric                                                       ReturnTy, IntrinParams);
16181ad6265SDimitry Andric   return Builder.CreateCall(VPDecl, IntrinParams, Name);
16281ad6265SDimitry Andric }
16381ad6265SDimitry Andric 
16481ad6265SDimitry Andric } // namespace llvm
165