blob: e7be7a98a593cdfc2690348e166ce83f15a6732c [file] [log] [blame]
//===- VectorBuilder.cpp - Builder for VP Intrinsics ----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the VectorBuilder class, which is used as a convenient
// way to create VP intrinsics as if they were LLVM instructions with a
// consistent and simplified interface.
//
//===----------------------------------------------------------------------===//
#include <llvm/ADT/SmallVector.h>
#include <llvm/IR/FPEnv.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/IntrinsicInst.h>
#include <llvm/IR/Intrinsics.h>
#include <llvm/IR/VectorBuilder.h>
namespace llvm {
void VectorBuilder::handleError(const char *ErrorMsg) const {
if (ErrorHandling == Behavior::SilentlyReturnNone)
return;
report_fatal_error(ErrorMsg);
}
Module &VectorBuilder::getModule() const {
return *Builder.GetInsertBlock()->getModule();
}
Value *VectorBuilder::getAllTrueMask() {
auto *BoolTy = Builder.getInt1Ty();
auto *MaskTy = VectorType::get(BoolTy, StaticVectorLength);
return ConstantInt::getAllOnesValue(MaskTy);
}
Value &VectorBuilder::requestMask() {
if (Mask)
return *Mask;
return *getAllTrueMask();
}
Value &VectorBuilder::requestEVL() {
if (ExplicitVectorLength)
return *ExplicitVectorLength;
assert(!StaticVectorLength.isScalable() && "TODO vscale lowering");
auto *IntTy = Builder.getInt32Ty();
return *ConstantInt::get(IntTy, StaticVectorLength.getFixedValue());
}
Value *VectorBuilder::createVectorInstruction(unsigned Opcode, Type *ReturnTy,
ArrayRef<Value *> InstOpArray,
const Twine &Name) {
auto VPID = VPIntrinsic::getForOpcode(Opcode);
if (VPID == Intrinsic::not_intrinsic)
return returnWithError<Value *>("No VPIntrinsic for this opcode");
auto MaskPosOpt = VPIntrinsic::getMaskParamPos(VPID);
auto VLenPosOpt = VPIntrinsic::getVectorLengthParamPos(VPID);
size_t NumInstParams = InstOpArray.size();
size_t NumVPParams =
NumInstParams + MaskPosOpt.has_value() + VLenPosOpt.has_value();
SmallVector<Value *, 6> IntrinParams;
// Whether the mask and vlen parameter are at the end of the parameter list.
bool TrailingMaskAndVLen =
std::min<size_t>(MaskPosOpt.value_or(NumInstParams),
VLenPosOpt.value_or(NumInstParams)) >= NumInstParams;
if (TrailingMaskAndVLen) {
// Fast path for trailing mask, vector length.
IntrinParams.append(InstOpArray.begin(), InstOpArray.end());
IntrinParams.resize(NumVPParams);
} else {
IntrinParams.resize(NumVPParams);
// Insert mask and evl operands in between the instruction operands.
for (size_t VPParamIdx = 0, ParamIdx = 0; VPParamIdx < NumVPParams;
++VPParamIdx) {
if ((MaskPosOpt && MaskPosOpt.value_or(NumVPParams) == VPParamIdx) ||
(VLenPosOpt && VLenPosOpt.value_or(NumVPParams) == VPParamIdx))
continue;
assert(ParamIdx < NumInstParams);
IntrinParams[VPParamIdx] = InstOpArray[ParamIdx++];
}
}
if (MaskPosOpt)
IntrinParams[*MaskPosOpt] = &requestMask();
if (VLenPosOpt)
IntrinParams[*VLenPosOpt] = &requestEVL();
auto *VPDecl = VPIntrinsic::getDeclarationForParams(&getModule(), VPID,
ReturnTy, IntrinParams);
return Builder.CreateCall(VPDecl, IntrinParams, Name);
}
} // namespace llvm