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