1*81ad6265SDimitry Andric //===- VectorBuilder.cpp - Builder for VP Intrinsics ----------------------===// 2*81ad6265SDimitry Andric // 3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*81ad6265SDimitry Andric // 7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 8*81ad6265SDimitry Andric // 9*81ad6265SDimitry Andric // This file implements the VectorBuilder class, which is used as a convenient 10*81ad6265SDimitry Andric // way to create VP intrinsics as if they were LLVM instructions with a 11*81ad6265SDimitry Andric // consistent and simplified interface. 12*81ad6265SDimitry Andric // 13*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 14*81ad6265SDimitry Andric 15*81ad6265SDimitry Andric #include <llvm/ADT/SmallVector.h> 16*81ad6265SDimitry Andric #include <llvm/IR/FPEnv.h> 17*81ad6265SDimitry Andric #include <llvm/IR/Instructions.h> 18*81ad6265SDimitry Andric #include <llvm/IR/IntrinsicInst.h> 19*81ad6265SDimitry Andric #include <llvm/IR/Intrinsics.h> 20*81ad6265SDimitry Andric #include <llvm/IR/VectorBuilder.h> 21*81ad6265SDimitry Andric 22*81ad6265SDimitry Andric namespace llvm { 23*81ad6265SDimitry Andric 24*81ad6265SDimitry Andric void VectorBuilder::handleError(const char *ErrorMsg) const { 25*81ad6265SDimitry Andric if (ErrorHandling == Behavior::SilentlyReturnNone) 26*81ad6265SDimitry Andric return; 27*81ad6265SDimitry Andric report_fatal_error(ErrorMsg); 28*81ad6265SDimitry Andric } 29*81ad6265SDimitry Andric 30*81ad6265SDimitry Andric Module &VectorBuilder::getModule() const { 31*81ad6265SDimitry Andric return *Builder.GetInsertBlock()->getModule(); 32*81ad6265SDimitry Andric } 33*81ad6265SDimitry Andric 34*81ad6265SDimitry Andric Value *VectorBuilder::getAllTrueMask() { 35*81ad6265SDimitry Andric auto *BoolTy = Builder.getInt1Ty(); 36*81ad6265SDimitry Andric auto *MaskTy = VectorType::get(BoolTy, StaticVectorLength); 37*81ad6265SDimitry Andric return ConstantInt::getAllOnesValue(MaskTy); 38*81ad6265SDimitry Andric } 39*81ad6265SDimitry Andric 40*81ad6265SDimitry Andric Value &VectorBuilder::requestMask() { 41*81ad6265SDimitry Andric if (Mask) 42*81ad6265SDimitry Andric return *Mask; 43*81ad6265SDimitry Andric 44*81ad6265SDimitry Andric return *getAllTrueMask(); 45*81ad6265SDimitry Andric } 46*81ad6265SDimitry Andric 47*81ad6265SDimitry Andric Value &VectorBuilder::requestEVL() { 48*81ad6265SDimitry Andric if (ExplicitVectorLength) 49*81ad6265SDimitry Andric return *ExplicitVectorLength; 50*81ad6265SDimitry Andric 51*81ad6265SDimitry Andric assert(!StaticVectorLength.isScalable() && "TODO vscale lowering"); 52*81ad6265SDimitry Andric auto *IntTy = Builder.getInt32Ty(); 53*81ad6265SDimitry Andric return *ConstantInt::get(IntTy, StaticVectorLength.getFixedValue()); 54*81ad6265SDimitry Andric } 55*81ad6265SDimitry Andric 56*81ad6265SDimitry Andric Value *VectorBuilder::createVectorInstruction(unsigned Opcode, Type *ReturnTy, 57*81ad6265SDimitry Andric ArrayRef<Value *> InstOpArray, 58*81ad6265SDimitry Andric const Twine &Name) { 59*81ad6265SDimitry Andric auto VPID = VPIntrinsic::getForOpcode(Opcode); 60*81ad6265SDimitry Andric if (VPID == Intrinsic::not_intrinsic) 61*81ad6265SDimitry Andric return returnWithError<Value *>("No VPIntrinsic for this opcode"); 62*81ad6265SDimitry Andric 63*81ad6265SDimitry Andric auto MaskPosOpt = VPIntrinsic::getMaskParamPos(VPID); 64*81ad6265SDimitry Andric auto VLenPosOpt = VPIntrinsic::getVectorLengthParamPos(VPID); 65*81ad6265SDimitry Andric size_t NumInstParams = InstOpArray.size(); 66*81ad6265SDimitry Andric size_t NumVPParams = 67*81ad6265SDimitry Andric NumInstParams + MaskPosOpt.has_value() + VLenPosOpt.has_value(); 68*81ad6265SDimitry Andric 69*81ad6265SDimitry Andric SmallVector<Value *, 6> IntrinParams; 70*81ad6265SDimitry Andric 71*81ad6265SDimitry Andric // Whether the mask and vlen parameter are at the end of the parameter list. 72*81ad6265SDimitry Andric bool TrailingMaskAndVLen = 73*81ad6265SDimitry Andric std::min<size_t>(MaskPosOpt.value_or(NumInstParams), 74*81ad6265SDimitry Andric VLenPosOpt.value_or(NumInstParams)) >= NumInstParams; 75*81ad6265SDimitry Andric 76*81ad6265SDimitry Andric if (TrailingMaskAndVLen) { 77*81ad6265SDimitry Andric // Fast path for trailing mask, vector length. 78*81ad6265SDimitry Andric IntrinParams.append(InstOpArray.begin(), InstOpArray.end()); 79*81ad6265SDimitry Andric IntrinParams.resize(NumVPParams); 80*81ad6265SDimitry Andric } else { 81*81ad6265SDimitry Andric IntrinParams.resize(NumVPParams); 82*81ad6265SDimitry Andric // Insert mask and evl operands in between the instruction operands. 83*81ad6265SDimitry Andric for (size_t VPParamIdx = 0, ParamIdx = 0; VPParamIdx < NumVPParams; 84*81ad6265SDimitry Andric ++VPParamIdx) { 85*81ad6265SDimitry Andric if ((MaskPosOpt && MaskPosOpt.value_or(NumVPParams) == VPParamIdx) || 86*81ad6265SDimitry Andric (VLenPosOpt && VLenPosOpt.value_or(NumVPParams) == VPParamIdx)) 87*81ad6265SDimitry Andric continue; 88*81ad6265SDimitry Andric assert(ParamIdx < NumInstParams); 89*81ad6265SDimitry Andric IntrinParams[VPParamIdx] = InstOpArray[ParamIdx++]; 90*81ad6265SDimitry Andric } 91*81ad6265SDimitry Andric } 92*81ad6265SDimitry Andric 93*81ad6265SDimitry Andric if (MaskPosOpt) 94*81ad6265SDimitry Andric IntrinParams[*MaskPosOpt] = &requestMask(); 95*81ad6265SDimitry Andric if (VLenPosOpt) 96*81ad6265SDimitry Andric IntrinParams[*VLenPosOpt] = &requestEVL(); 97*81ad6265SDimitry Andric 98*81ad6265SDimitry Andric auto *VPDecl = VPIntrinsic::getDeclarationForParams(&getModule(), VPID, 99*81ad6265SDimitry Andric ReturnTy, IntrinParams); 100*81ad6265SDimitry Andric return Builder.CreateCall(VPDecl, IntrinParams, Name); 101*81ad6265SDimitry Andric } 102*81ad6265SDimitry Andric 103*81ad6265SDimitry Andric } // namespace llvm 104