Path: blob/main/contrib/llvm-project/llvm/lib/IR/IntrinsicInst.cpp
35233 views
//===-- IntrinsicInst.cpp - Intrinsic Instruction Wrappers ---------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements methods that make it really easy to deal with intrinsic9// functions.10//11// All intrinsic function calls are instances of the call instruction, so these12// are all subclasses of the CallInst class. Note that none of these classes13// has state or virtual methods, which is an important part of this gross/neat14// hack working.15//16// In some cases, arguments to intrinsics need to be generic and are defined as17// type pointer to empty struct { }*. To access the real item of interest the18// cast instruction needs to be stripped away.19//20//===----------------------------------------------------------------------===//2122#include "llvm/IR/IntrinsicInst.h"23#include "llvm/ADT/StringSwitch.h"24#include "llvm/IR/Constants.h"25#include "llvm/IR/DebugInfoMetadata.h"26#include "llvm/IR/Metadata.h"27#include "llvm/IR/Module.h"28#include "llvm/IR/Operator.h"29#include "llvm/IR/PatternMatch.h"30#include "llvm/IR/Statepoint.h"31#include <optional>3233using namespace llvm;3435bool IntrinsicInst::mayLowerToFunctionCall(Intrinsic::ID IID) {36switch (IID) {37case Intrinsic::objc_autorelease:38case Intrinsic::objc_autoreleasePoolPop:39case Intrinsic::objc_autoreleasePoolPush:40case Intrinsic::objc_autoreleaseReturnValue:41case Intrinsic::objc_copyWeak:42case Intrinsic::objc_destroyWeak:43case Intrinsic::objc_initWeak:44case Intrinsic::objc_loadWeak:45case Intrinsic::objc_loadWeakRetained:46case Intrinsic::objc_moveWeak:47case Intrinsic::objc_release:48case Intrinsic::objc_retain:49case Intrinsic::objc_retainAutorelease:50case Intrinsic::objc_retainAutoreleaseReturnValue:51case Intrinsic::objc_retainAutoreleasedReturnValue:52case Intrinsic::objc_retainBlock:53case Intrinsic::objc_storeStrong:54case Intrinsic::objc_storeWeak:55case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue:56case Intrinsic::objc_retainedObject:57case Intrinsic::objc_unretainedObject:58case Intrinsic::objc_unretainedPointer:59case Intrinsic::objc_retain_autorelease:60case Intrinsic::objc_sync_enter:61case Intrinsic::objc_sync_exit:62return true;63default:64return false;65}66}6768//===----------------------------------------------------------------------===//69/// DbgVariableIntrinsic - This is the common base class for debug info70/// intrinsics for variables.71///7273iterator_range<location_op_iterator> RawLocationWrapper::location_ops() const {74Metadata *MD = getRawLocation();75assert(MD && "First operand of DbgVariableIntrinsic should be non-null.");76// If operand is ValueAsMetadata, return a range over just that operand.77if (auto *VAM = dyn_cast<ValueAsMetadata>(MD)) {78return {location_op_iterator(VAM), location_op_iterator(VAM + 1)};79}80// If operand is DIArgList, return a range over its args.81if (auto *AL = dyn_cast<DIArgList>(MD))82return {location_op_iterator(AL->args_begin()),83location_op_iterator(AL->args_end())};84// Operand must be an empty metadata tuple, so return empty iterator.85return {location_op_iterator(static_cast<ValueAsMetadata *>(nullptr)),86location_op_iterator(static_cast<ValueAsMetadata *>(nullptr))};87}8889iterator_range<location_op_iterator>90DbgVariableIntrinsic::location_ops() const {91return getWrappedLocation().location_ops();92}9394Value *DbgVariableIntrinsic::getVariableLocationOp(unsigned OpIdx) const {95return getWrappedLocation().getVariableLocationOp(OpIdx);96}9798Value *RawLocationWrapper::getVariableLocationOp(unsigned OpIdx) const {99Metadata *MD = getRawLocation();100assert(MD && "First operand of DbgVariableIntrinsic should be non-null.");101if (auto *AL = dyn_cast<DIArgList>(MD))102return AL->getArgs()[OpIdx]->getValue();103if (isa<MDNode>(MD))104return nullptr;105assert(106isa<ValueAsMetadata>(MD) &&107"Attempted to get location operand from DbgVariableIntrinsic with none.");108auto *V = cast<ValueAsMetadata>(MD);109assert(OpIdx == 0 && "Operand Index must be 0 for a debug intrinsic with a "110"single location operand.");111return V->getValue();112}113114static ValueAsMetadata *getAsMetadata(Value *V) {115return isa<MetadataAsValue>(V) ? dyn_cast<ValueAsMetadata>(116cast<MetadataAsValue>(V)->getMetadata())117: ValueAsMetadata::get(V);118}119120void DbgVariableIntrinsic::replaceVariableLocationOp(Value *OldValue,121Value *NewValue,122bool AllowEmpty) {123// If OldValue is used as the address part of a dbg.assign intrinsic replace124// it with NewValue and return true.125auto ReplaceDbgAssignAddress = [this, OldValue, NewValue]() -> bool {126auto *DAI = dyn_cast<DbgAssignIntrinsic>(this);127if (!DAI || OldValue != DAI->getAddress())128return false;129DAI->setAddress(NewValue);130return true;131};132bool DbgAssignAddrReplaced = ReplaceDbgAssignAddress();133(void)DbgAssignAddrReplaced;134135assert(NewValue && "Values must be non-null");136auto Locations = location_ops();137auto OldIt = find(Locations, OldValue);138if (OldIt == Locations.end()) {139if (AllowEmpty || DbgAssignAddrReplaced)140return;141assert(DbgAssignAddrReplaced &&142"OldValue must be dbg.assign addr if unused in DIArgList");143return;144}145146assert(OldIt != Locations.end() && "OldValue must be a current location");147if (!hasArgList()) {148Value *NewOperand = isa<MetadataAsValue>(NewValue)149? NewValue150: MetadataAsValue::get(151getContext(), ValueAsMetadata::get(NewValue));152return setArgOperand(0, NewOperand);153}154SmallVector<ValueAsMetadata *, 4> MDs;155ValueAsMetadata *NewOperand = getAsMetadata(NewValue);156for (auto *VMD : Locations)157MDs.push_back(VMD == *OldIt ? NewOperand : getAsMetadata(VMD));158setArgOperand(1590, MetadataAsValue::get(getContext(), DIArgList::get(getContext(), MDs)));160}161void DbgVariableIntrinsic::replaceVariableLocationOp(unsigned OpIdx,162Value *NewValue) {163assert(OpIdx < getNumVariableLocationOps() && "Invalid Operand Index");164if (!hasArgList()) {165Value *NewOperand = isa<MetadataAsValue>(NewValue)166? NewValue167: MetadataAsValue::get(168getContext(), ValueAsMetadata::get(NewValue));169return setArgOperand(0, NewOperand);170}171SmallVector<ValueAsMetadata *, 4> MDs;172ValueAsMetadata *NewOperand = getAsMetadata(NewValue);173for (unsigned Idx = 0; Idx < getNumVariableLocationOps(); ++Idx)174MDs.push_back(Idx == OpIdx ? NewOperand175: getAsMetadata(getVariableLocationOp(Idx)));176setArgOperand(1770, MetadataAsValue::get(getContext(), DIArgList::get(getContext(), MDs)));178}179180void DbgVariableIntrinsic::addVariableLocationOps(ArrayRef<Value *> NewValues,181DIExpression *NewExpr) {182assert(NewExpr->hasAllLocationOps(getNumVariableLocationOps() +183NewValues.size()) &&184"NewExpr for debug variable intrinsic does not reference every "185"location operand.");186assert(!is_contained(NewValues, nullptr) && "New values must be non-null");187setArgOperand(2, MetadataAsValue::get(getContext(), NewExpr));188SmallVector<ValueAsMetadata *, 4> MDs;189for (auto *VMD : location_ops())190MDs.push_back(getAsMetadata(VMD));191for (auto *VMD : NewValues)192MDs.push_back(getAsMetadata(VMD));193setArgOperand(1940, MetadataAsValue::get(getContext(), DIArgList::get(getContext(), MDs)));195}196197std::optional<uint64_t> DbgVariableIntrinsic::getFragmentSizeInBits() const {198if (auto Fragment = getExpression()->getFragmentInfo())199return Fragment->SizeInBits;200return getVariable()->getSizeInBits();201}202203Value *DbgAssignIntrinsic::getAddress() const {204auto *MD = getRawAddress();205if (auto *V = dyn_cast<ValueAsMetadata>(MD))206return V->getValue();207208// When the value goes to null, it gets replaced by an empty MDNode.209assert(!cast<MDNode>(MD)->getNumOperands() && "Expected an empty MDNode");210return nullptr;211}212213void DbgAssignIntrinsic::setAssignId(DIAssignID *New) {214setOperand(OpAssignID, MetadataAsValue::get(getContext(), New));215}216217void DbgAssignIntrinsic::setAddress(Value *V) {218setOperand(OpAddress,219MetadataAsValue::get(getContext(), ValueAsMetadata::get(V)));220}221222void DbgAssignIntrinsic::setKillAddress() {223if (isKillAddress())224return;225setAddress(UndefValue::get(getAddress()->getType()));226}227228bool DbgAssignIntrinsic::isKillAddress() const {229Value *Addr = getAddress();230return !Addr || isa<UndefValue>(Addr);231}232233void DbgAssignIntrinsic::setValue(Value *V) {234setOperand(OpValue,235MetadataAsValue::get(getContext(), ValueAsMetadata::get(V)));236}237238int llvm::Intrinsic::lookupLLVMIntrinsicByName(ArrayRef<const char *> NameTable,239StringRef Name) {240assert(Name.starts_with("llvm.") && "Unexpected intrinsic prefix");241242// Do successive binary searches of the dotted name components. For243// "llvm.gc.experimental.statepoint.p1i8.p1i32", we will find the range of244// intrinsics starting with "llvm.gc", then "llvm.gc.experimental", then245// "llvm.gc.experimental.statepoint", and then we will stop as the range is246// size 1. During the search, we can skip the prefix that we already know is247// identical. By using strncmp we consider names with differing suffixes to248// be part of the equal range.249size_t CmpEnd = 4; // Skip the "llvm" component.250const char *const *Low = NameTable.begin();251const char *const *High = NameTable.end();252const char *const *LastLow = Low;253while (CmpEnd < Name.size() && High - Low > 0) {254size_t CmpStart = CmpEnd;255CmpEnd = Name.find('.', CmpStart + 1);256CmpEnd = CmpEnd == StringRef::npos ? Name.size() : CmpEnd;257auto Cmp = [CmpStart, CmpEnd](const char *LHS, const char *RHS) {258return strncmp(LHS + CmpStart, RHS + CmpStart, CmpEnd - CmpStart) < 0;259};260LastLow = Low;261std::tie(Low, High) = std::equal_range(Low, High, Name.data(), Cmp);262}263if (High - Low > 0)264LastLow = Low;265266if (LastLow == NameTable.end())267return -1;268StringRef NameFound = *LastLow;269if (Name == NameFound ||270(Name.starts_with(NameFound) && Name[NameFound.size()] == '.'))271return LastLow - NameTable.begin();272return -1;273}274275ConstantInt *InstrProfCntrInstBase::getNumCounters() const {276if (InstrProfValueProfileInst::classof(this))277llvm_unreachable("InstrProfValueProfileInst does not have counters!");278return cast<ConstantInt>(const_cast<Value *>(getArgOperand(2)));279}280281ConstantInt *InstrProfCntrInstBase::getIndex() const {282if (InstrProfValueProfileInst::classof(this))283llvm_unreachable("Please use InstrProfValueProfileInst::getIndex()");284return cast<ConstantInt>(const_cast<Value *>(getArgOperand(3)));285}286287Value *InstrProfIncrementInst::getStep() const {288if (InstrProfIncrementInstStep::classof(this)) {289return const_cast<Value *>(getArgOperand(4));290}291const Module *M = getModule();292LLVMContext &Context = M->getContext();293return ConstantInt::get(Type::getInt64Ty(Context), 1);294}295296Value *InstrProfCallsite::getCallee() const {297if (isa<InstrProfCallsite>(this))298return getArgOperand(4);299return nullptr;300}301302std::optional<RoundingMode> ConstrainedFPIntrinsic::getRoundingMode() const {303unsigned NumOperands = arg_size();304Metadata *MD = nullptr;305auto *MAV = dyn_cast<MetadataAsValue>(getArgOperand(NumOperands - 2));306if (MAV)307MD = MAV->getMetadata();308if (!MD || !isa<MDString>(MD))309return std::nullopt;310return convertStrToRoundingMode(cast<MDString>(MD)->getString());311}312313std::optional<fp::ExceptionBehavior>314ConstrainedFPIntrinsic::getExceptionBehavior() const {315unsigned NumOperands = arg_size();316Metadata *MD = nullptr;317auto *MAV = dyn_cast<MetadataAsValue>(getArgOperand(NumOperands - 1));318if (MAV)319MD = MAV->getMetadata();320if (!MD || !isa<MDString>(MD))321return std::nullopt;322return convertStrToExceptionBehavior(cast<MDString>(MD)->getString());323}324325bool ConstrainedFPIntrinsic::isDefaultFPEnvironment() const {326std::optional<fp::ExceptionBehavior> Except = getExceptionBehavior();327if (Except) {328if (*Except != fp::ebIgnore)329return false;330}331332std::optional<RoundingMode> Rounding = getRoundingMode();333if (Rounding) {334if (*Rounding != RoundingMode::NearestTiesToEven)335return false;336}337338return true;339}340341static FCmpInst::Predicate getFPPredicateFromMD(const Value *Op) {342Metadata *MD = cast<MetadataAsValue>(Op)->getMetadata();343if (!MD || !isa<MDString>(MD))344return FCmpInst::BAD_FCMP_PREDICATE;345return StringSwitch<FCmpInst::Predicate>(cast<MDString>(MD)->getString())346.Case("oeq", FCmpInst::FCMP_OEQ)347.Case("ogt", FCmpInst::FCMP_OGT)348.Case("oge", FCmpInst::FCMP_OGE)349.Case("olt", FCmpInst::FCMP_OLT)350.Case("ole", FCmpInst::FCMP_OLE)351.Case("one", FCmpInst::FCMP_ONE)352.Case("ord", FCmpInst::FCMP_ORD)353.Case("uno", FCmpInst::FCMP_UNO)354.Case("ueq", FCmpInst::FCMP_UEQ)355.Case("ugt", FCmpInst::FCMP_UGT)356.Case("uge", FCmpInst::FCMP_UGE)357.Case("ult", FCmpInst::FCMP_ULT)358.Case("ule", FCmpInst::FCMP_ULE)359.Case("une", FCmpInst::FCMP_UNE)360.Default(FCmpInst::BAD_FCMP_PREDICATE);361}362363FCmpInst::Predicate ConstrainedFPCmpIntrinsic::getPredicate() const {364return getFPPredicateFromMD(getArgOperand(2));365}366367unsigned ConstrainedFPIntrinsic::getNonMetadataArgCount() const {368// All constrained fp intrinsics have "fpexcept" metadata.369unsigned NumArgs = arg_size() - 1;370371// Some intrinsics have "round" metadata.372if (Intrinsic::hasConstrainedFPRoundingModeOperand(getIntrinsicID()))373NumArgs -= 1;374375// Compare intrinsics take their predicate as metadata.376if (isa<ConstrainedFPCmpIntrinsic>(this))377NumArgs -= 1;378379return NumArgs;380}381382bool ConstrainedFPIntrinsic::classof(const IntrinsicInst *I) {383return Intrinsic::isConstrainedFPIntrinsic(I->getIntrinsicID());384}385386ElementCount VPIntrinsic::getStaticVectorLength() const {387auto GetVectorLengthOfType = [](const Type *T) -> ElementCount {388const auto *VT = cast<VectorType>(T);389auto ElemCount = VT->getElementCount();390return ElemCount;391};392393Value *VPMask = getMaskParam();394if (!VPMask) {395assert((getIntrinsicID() == Intrinsic::vp_merge ||396getIntrinsicID() == Intrinsic::vp_select) &&397"Unexpected VP intrinsic without mask operand");398return GetVectorLengthOfType(getType());399}400return GetVectorLengthOfType(VPMask->getType());401}402403Value *VPIntrinsic::getMaskParam() const {404if (auto MaskPos = getMaskParamPos(getIntrinsicID()))405return getArgOperand(*MaskPos);406return nullptr;407}408409void VPIntrinsic::setMaskParam(Value *NewMask) {410auto MaskPos = getMaskParamPos(getIntrinsicID());411setArgOperand(*MaskPos, NewMask);412}413414Value *VPIntrinsic::getVectorLengthParam() const {415if (auto EVLPos = getVectorLengthParamPos(getIntrinsicID()))416return getArgOperand(*EVLPos);417return nullptr;418}419420void VPIntrinsic::setVectorLengthParam(Value *NewEVL) {421auto EVLPos = getVectorLengthParamPos(getIntrinsicID());422setArgOperand(*EVLPos, NewEVL);423}424425std::optional<unsigned>426VPIntrinsic::getMaskParamPos(Intrinsic::ID IntrinsicID) {427switch (IntrinsicID) {428default:429return std::nullopt;430431#define BEGIN_REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \432case Intrinsic::VPID: \433return MASKPOS;434#include "llvm/IR/VPIntrinsics.def"435}436}437438std::optional<unsigned>439VPIntrinsic::getVectorLengthParamPos(Intrinsic::ID IntrinsicID) {440switch (IntrinsicID) {441default:442return std::nullopt;443444#define BEGIN_REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \445case Intrinsic::VPID: \446return VLENPOS;447#include "llvm/IR/VPIntrinsics.def"448}449}450451/// \return the alignment of the pointer used by this load/store/gather or452/// scatter.453MaybeAlign VPIntrinsic::getPointerAlignment() const {454std::optional<unsigned> PtrParamOpt =455getMemoryPointerParamPos(getIntrinsicID());456assert(PtrParamOpt && "no pointer argument!");457return getParamAlign(*PtrParamOpt);458}459460/// \return The pointer operand of this load,store, gather or scatter.461Value *VPIntrinsic::getMemoryPointerParam() const {462if (auto PtrParamOpt = getMemoryPointerParamPos(getIntrinsicID()))463return getArgOperand(*PtrParamOpt);464return nullptr;465}466467std::optional<unsigned>468VPIntrinsic::getMemoryPointerParamPos(Intrinsic::ID VPID) {469switch (VPID) {470default:471break;472#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:473#define VP_PROPERTY_MEMOP(POINTERPOS, ...) return POINTERPOS;474#define END_REGISTER_VP_INTRINSIC(VPID) break;475#include "llvm/IR/VPIntrinsics.def"476}477return std::nullopt;478}479480/// \return The data (payload) operand of this store or scatter.481Value *VPIntrinsic::getMemoryDataParam() const {482auto DataParamOpt = getMemoryDataParamPos(getIntrinsicID());483if (!DataParamOpt)484return nullptr;485return getArgOperand(*DataParamOpt);486}487488std::optional<unsigned> VPIntrinsic::getMemoryDataParamPos(Intrinsic::ID VPID) {489switch (VPID) {490default:491break;492#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:493#define VP_PROPERTY_MEMOP(POINTERPOS, DATAPOS) return DATAPOS;494#define END_REGISTER_VP_INTRINSIC(VPID) break;495#include "llvm/IR/VPIntrinsics.def"496}497return std::nullopt;498}499500constexpr bool isVPIntrinsic(Intrinsic::ID ID) {501switch (ID) {502default:503break;504#define BEGIN_REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \505case Intrinsic::VPID: \506return true;507#include "llvm/IR/VPIntrinsics.def"508}509return false;510}511512bool VPIntrinsic::isVPIntrinsic(Intrinsic::ID ID) {513return ::isVPIntrinsic(ID);514}515516// Equivalent non-predicated opcode517constexpr static std::optional<unsigned>518getFunctionalOpcodeForVP(Intrinsic::ID ID) {519switch (ID) {520default:521break;522#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:523#define VP_PROPERTY_FUNCTIONAL_OPC(OPC) return Instruction::OPC;524#define END_REGISTER_VP_INTRINSIC(VPID) break;525#include "llvm/IR/VPIntrinsics.def"526}527return std::nullopt;528}529530std::optional<unsigned>531VPIntrinsic::getFunctionalOpcodeForVP(Intrinsic::ID ID) {532return ::getFunctionalOpcodeForVP(ID);533}534535// Equivalent non-predicated intrinsic ID536constexpr static std::optional<Intrinsic::ID>537getFunctionalIntrinsicIDForVP(Intrinsic::ID ID) {538switch (ID) {539default:540break;541#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:542#define VP_PROPERTY_FUNCTIONAL_INTRINSIC(INTRIN) return Intrinsic::INTRIN;543#define END_REGISTER_VP_INTRINSIC(VPID) break;544#include "llvm/IR/VPIntrinsics.def"545}546return std::nullopt;547}548549std::optional<Intrinsic::ID>550VPIntrinsic::getFunctionalIntrinsicIDForVP(Intrinsic::ID ID) {551return ::getFunctionalIntrinsicIDForVP(ID);552}553554constexpr static bool doesVPHaveNoFunctionalEquivalent(Intrinsic::ID ID) {555switch (ID) {556default:557break;558#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:559#define VP_PROPERTY_NO_FUNCTIONAL return true;560#define END_REGISTER_VP_INTRINSIC(VPID) break;561#include "llvm/IR/VPIntrinsics.def"562}563return false;564}565566// All VP intrinsics should have an equivalent non-VP opcode or intrinsic567// defined, or be marked that they don't have one.568#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) \569static_assert(doesVPHaveNoFunctionalEquivalent(Intrinsic::VPID) || \570getFunctionalOpcodeForVP(Intrinsic::VPID) || \571getFunctionalIntrinsicIDForVP(Intrinsic::VPID));572#include "llvm/IR/VPIntrinsics.def"573574// Equivalent non-predicated constrained intrinsic575std::optional<Intrinsic::ID>576VPIntrinsic::getConstrainedIntrinsicIDForVP(Intrinsic::ID ID) {577switch (ID) {578default:579break;580#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:581#define VP_PROPERTY_CONSTRAINEDFP(HASRND, HASEXCEPT, CID) return Intrinsic::CID;582#define END_REGISTER_VP_INTRINSIC(VPID) break;583#include "llvm/IR/VPIntrinsics.def"584}585return std::nullopt;586}587588Intrinsic::ID VPIntrinsic::getForOpcode(unsigned IROPC) {589switch (IROPC) {590default:591break;592593#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) break;594#define VP_PROPERTY_FUNCTIONAL_OPC(OPC) case Instruction::OPC:595#define END_REGISTER_VP_INTRINSIC(VPID) return Intrinsic::VPID;596#include "llvm/IR/VPIntrinsics.def"597}598return Intrinsic::not_intrinsic;599}600601constexpr static Intrinsic::ID getForIntrinsic(Intrinsic::ID Id) {602if (::isVPIntrinsic(Id))603return Id;604605switch (Id) {606default:607break;608#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) break;609#define VP_PROPERTY_FUNCTIONAL_INTRINSIC(INTRIN) case Intrinsic::INTRIN:610#define END_REGISTER_VP_INTRINSIC(VPID) return Intrinsic::VPID;611#include "llvm/IR/VPIntrinsics.def"612}613return Intrinsic::not_intrinsic;614}615616Intrinsic::ID VPIntrinsic::getForIntrinsic(Intrinsic::ID Id) {617return ::getForIntrinsic(Id);618}619620bool VPIntrinsic::canIgnoreVectorLengthParam() const {621using namespace PatternMatch;622623ElementCount EC = getStaticVectorLength();624625// No vlen param - no lanes masked-off by it.626auto *VLParam = getVectorLengthParam();627if (!VLParam)628return true;629630// Note that the VP intrinsic causes undefined behavior if the Explicit Vector631// Length parameter is strictly greater-than the number of vector elements of632// the operation. This function returns true when this is detected statically633// in the IR.634635// Check whether "W == vscale * EC.getKnownMinValue()"636if (EC.isScalable()) {637// Compare vscale patterns638uint64_t VScaleFactor;639if (match(VLParam, m_Mul(m_VScale(), m_ConstantInt(VScaleFactor))))640return VScaleFactor >= EC.getKnownMinValue();641return (EC.getKnownMinValue() == 1) && match(VLParam, m_VScale());642}643644// standard SIMD operation645const auto *VLConst = dyn_cast<ConstantInt>(VLParam);646if (!VLConst)647return false;648649uint64_t VLNum = VLConst->getZExtValue();650if (VLNum >= EC.getKnownMinValue())651return true;652653return false;654}655656Function *VPIntrinsic::getDeclarationForParams(Module *M, Intrinsic::ID VPID,657Type *ReturnType,658ArrayRef<Value *> Params) {659assert(isVPIntrinsic(VPID) && "not a VP intrinsic");660Function *VPFunc;661switch (VPID) {662default: {663Type *OverloadTy = Params[0]->getType();664if (VPReductionIntrinsic::isVPReduction(VPID))665OverloadTy =666Params[*VPReductionIntrinsic::getVectorParamPos(VPID)]->getType();667668VPFunc = Intrinsic::getDeclaration(M, VPID, OverloadTy);669break;670}671case Intrinsic::vp_trunc:672case Intrinsic::vp_sext:673case Intrinsic::vp_zext:674case Intrinsic::vp_fptoui:675case Intrinsic::vp_fptosi:676case Intrinsic::vp_uitofp:677case Intrinsic::vp_sitofp:678case Intrinsic::vp_fptrunc:679case Intrinsic::vp_fpext:680case Intrinsic::vp_ptrtoint:681case Intrinsic::vp_inttoptr:682case Intrinsic::vp_lrint:683case Intrinsic::vp_llrint:684case Intrinsic::vp_cttz_elts:685VPFunc =686Intrinsic::getDeclaration(M, VPID, {ReturnType, Params[0]->getType()});687break;688case Intrinsic::vp_is_fpclass:689VPFunc = Intrinsic::getDeclaration(M, VPID, {Params[0]->getType()});690break;691case Intrinsic::vp_merge:692case Intrinsic::vp_select:693VPFunc = Intrinsic::getDeclaration(M, VPID, {Params[1]->getType()});694break;695case Intrinsic::vp_load:696VPFunc = Intrinsic::getDeclaration(697M, VPID, {ReturnType, Params[0]->getType()});698break;699case Intrinsic::experimental_vp_strided_load:700VPFunc = Intrinsic::getDeclaration(701M, VPID, {ReturnType, Params[0]->getType(), Params[1]->getType()});702break;703case Intrinsic::vp_gather:704VPFunc = Intrinsic::getDeclaration(705M, VPID, {ReturnType, Params[0]->getType()});706break;707case Intrinsic::vp_store:708VPFunc = Intrinsic::getDeclaration(709M, VPID, {Params[0]->getType(), Params[1]->getType()});710break;711case Intrinsic::experimental_vp_strided_store:712VPFunc = Intrinsic::getDeclaration(713M, VPID,714{Params[0]->getType(), Params[1]->getType(), Params[2]->getType()});715break;716case Intrinsic::vp_scatter:717VPFunc = Intrinsic::getDeclaration(718M, VPID, {Params[0]->getType(), Params[1]->getType()});719break;720case Intrinsic::experimental_vp_splat:721VPFunc = Intrinsic::getDeclaration(M, VPID, ReturnType);722break;723}724assert(VPFunc && "Could not declare VP intrinsic");725return VPFunc;726}727728bool VPReductionIntrinsic::isVPReduction(Intrinsic::ID ID) {729switch (ID) {730default:731break;732#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:733#define VP_PROPERTY_REDUCTION(STARTPOS, ...) return true;734#define END_REGISTER_VP_INTRINSIC(VPID) break;735#include "llvm/IR/VPIntrinsics.def"736}737return false;738}739740bool VPCastIntrinsic::isVPCast(Intrinsic::ID ID) {741switch (ID) {742default:743break;744#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:745#define VP_PROPERTY_CASTOP return true;746#define END_REGISTER_VP_INTRINSIC(VPID) break;747#include "llvm/IR/VPIntrinsics.def"748}749return false;750}751752bool VPCmpIntrinsic::isVPCmp(Intrinsic::ID ID) {753switch (ID) {754default:755break;756#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:757#define VP_PROPERTY_CMP(CCPOS, ...) return true;758#define END_REGISTER_VP_INTRINSIC(VPID) break;759#include "llvm/IR/VPIntrinsics.def"760}761return false;762}763764bool VPBinOpIntrinsic::isVPBinOp(Intrinsic::ID ID) {765switch (ID) {766default:767break;768#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:769#define VP_PROPERTY_BINARYOP return true;770#define END_REGISTER_VP_INTRINSIC(VPID) break;771#include "llvm/IR/VPIntrinsics.def"772}773return false;774}775776static ICmpInst::Predicate getIntPredicateFromMD(const Value *Op) {777Metadata *MD = cast<MetadataAsValue>(Op)->getMetadata();778if (!MD || !isa<MDString>(MD))779return ICmpInst::BAD_ICMP_PREDICATE;780return StringSwitch<ICmpInst::Predicate>(cast<MDString>(MD)->getString())781.Case("eq", ICmpInst::ICMP_EQ)782.Case("ne", ICmpInst::ICMP_NE)783.Case("ugt", ICmpInst::ICMP_UGT)784.Case("uge", ICmpInst::ICMP_UGE)785.Case("ult", ICmpInst::ICMP_ULT)786.Case("ule", ICmpInst::ICMP_ULE)787.Case("sgt", ICmpInst::ICMP_SGT)788.Case("sge", ICmpInst::ICMP_SGE)789.Case("slt", ICmpInst::ICMP_SLT)790.Case("sle", ICmpInst::ICMP_SLE)791.Default(ICmpInst::BAD_ICMP_PREDICATE);792}793794CmpInst::Predicate VPCmpIntrinsic::getPredicate() const {795bool IsFP = true;796std::optional<unsigned> CCArgIdx;797switch (getIntrinsicID()) {798default:799break;800#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:801#define VP_PROPERTY_CMP(CCPOS, ISFP) \802CCArgIdx = CCPOS; \803IsFP = ISFP; \804break;805#define END_REGISTER_VP_INTRINSIC(VPID) break;806#include "llvm/IR/VPIntrinsics.def"807}808assert(CCArgIdx && "Unexpected vector-predicated comparison");809return IsFP ? getFPPredicateFromMD(getArgOperand(*CCArgIdx))810: getIntPredicateFromMD(getArgOperand(*CCArgIdx));811}812813unsigned VPReductionIntrinsic::getVectorParamPos() const {814return *VPReductionIntrinsic::getVectorParamPos(getIntrinsicID());815}816817unsigned VPReductionIntrinsic::getStartParamPos() const {818return *VPReductionIntrinsic::getStartParamPos(getIntrinsicID());819}820821std::optional<unsigned>822VPReductionIntrinsic::getVectorParamPos(Intrinsic::ID ID) {823switch (ID) {824#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:825#define VP_PROPERTY_REDUCTION(STARTPOS, VECTORPOS) return VECTORPOS;826#define END_REGISTER_VP_INTRINSIC(VPID) break;827#include "llvm/IR/VPIntrinsics.def"828default:829break;830}831return std::nullopt;832}833834std::optional<unsigned>835VPReductionIntrinsic::getStartParamPos(Intrinsic::ID ID) {836switch (ID) {837#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:838#define VP_PROPERTY_REDUCTION(STARTPOS, VECTORPOS) return STARTPOS;839#define END_REGISTER_VP_INTRINSIC(VPID) break;840#include "llvm/IR/VPIntrinsics.def"841default:842break;843}844return std::nullopt;845}846847Instruction::BinaryOps BinaryOpIntrinsic::getBinaryOp() const {848switch (getIntrinsicID()) {849case Intrinsic::uadd_with_overflow:850case Intrinsic::sadd_with_overflow:851case Intrinsic::uadd_sat:852case Intrinsic::sadd_sat:853return Instruction::Add;854case Intrinsic::usub_with_overflow:855case Intrinsic::ssub_with_overflow:856case Intrinsic::usub_sat:857case Intrinsic::ssub_sat:858return Instruction::Sub;859case Intrinsic::umul_with_overflow:860case Intrinsic::smul_with_overflow:861return Instruction::Mul;862default:863llvm_unreachable("Invalid intrinsic");864}865}866867bool BinaryOpIntrinsic::isSigned() const {868switch (getIntrinsicID()) {869case Intrinsic::sadd_with_overflow:870case Intrinsic::ssub_with_overflow:871case Intrinsic::smul_with_overflow:872case Intrinsic::sadd_sat:873case Intrinsic::ssub_sat:874return true;875default:876return false;877}878}879880unsigned BinaryOpIntrinsic::getNoWrapKind() const {881if (isSigned())882return OverflowingBinaryOperator::NoSignedWrap;883else884return OverflowingBinaryOperator::NoUnsignedWrap;885}886887const Value *GCProjectionInst::getStatepoint() const {888const Value *Token = getArgOperand(0);889if (isa<UndefValue>(Token))890return Token;891892// Treat none token as if it was undef here893if (isa<ConstantTokenNone>(Token))894return UndefValue::get(Token->getType());895896// This takes care both of relocates for call statepoints and relocates897// on normal path of invoke statepoint.898if (!isa<LandingPadInst>(Token))899return cast<GCStatepointInst>(Token);900901// This relocate is on exceptional path of an invoke statepoint902const BasicBlock *InvokeBB =903cast<Instruction>(Token)->getParent()->getUniquePredecessor();904905assert(InvokeBB && "safepoints should have unique landingpads");906assert(InvokeBB->getTerminator() &&907"safepoint block should be well formed");908909return cast<GCStatepointInst>(InvokeBB->getTerminator());910}911912Value *GCRelocateInst::getBasePtr() const {913auto Statepoint = getStatepoint();914if (isa<UndefValue>(Statepoint))915return UndefValue::get(Statepoint->getType());916917auto *GCInst = cast<GCStatepointInst>(Statepoint);918if (auto Opt = GCInst->getOperandBundle(LLVMContext::OB_gc_live))919return *(Opt->Inputs.begin() + getBasePtrIndex());920return *(GCInst->arg_begin() + getBasePtrIndex());921}922923Value *GCRelocateInst::getDerivedPtr() const {924auto *Statepoint = getStatepoint();925if (isa<UndefValue>(Statepoint))926return UndefValue::get(Statepoint->getType());927928auto *GCInst = cast<GCStatepointInst>(Statepoint);929if (auto Opt = GCInst->getOperandBundle(LLVMContext::OB_gc_live))930return *(Opt->Inputs.begin() + getDerivedPtrIndex());931return *(GCInst->arg_begin() + getDerivedPtrIndex());932}933934935