123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833 |
- //===-- IntrinsicInst.cpp - Intrinsic Instruction Wrappers ---------------===//
- //
- // 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 methods that make it really easy to deal with intrinsic
- // functions.
- //
- // All intrinsic function calls are instances of the call instruction, so these
- // are all subclasses of the CallInst class. Note that none of these classes
- // has state or virtual methods, which is an important part of this gross/neat
- // hack working.
- //
- // In some cases, arguments to intrinsics need to be generic and are defined as
- // type pointer to empty struct { }*. To access the real item of interest the
- // cast instruction needs to be stripped away.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/IR/IntrinsicInst.h"
- #include "llvm/ADT/StringSwitch.h"
- #include "llvm/IR/Constants.h"
- #include "llvm/IR/DebugInfoMetadata.h"
- #include "llvm/IR/Metadata.h"
- #include "llvm/IR/Module.h"
- #include "llvm/IR/Operator.h"
- #include "llvm/IR/PatternMatch.h"
- #include "llvm/IR/Statepoint.h"
- #include <optional>
- using namespace llvm;
- bool IntrinsicInst::mayLowerToFunctionCall(Intrinsic::ID IID) {
- switch (IID) {
- case Intrinsic::objc_autorelease:
- case Intrinsic::objc_autoreleasePoolPop:
- case Intrinsic::objc_autoreleasePoolPush:
- case Intrinsic::objc_autoreleaseReturnValue:
- case Intrinsic::objc_copyWeak:
- case Intrinsic::objc_destroyWeak:
- case Intrinsic::objc_initWeak:
- case Intrinsic::objc_loadWeak:
- case Intrinsic::objc_loadWeakRetained:
- case Intrinsic::objc_moveWeak:
- case Intrinsic::objc_release:
- case Intrinsic::objc_retain:
- case Intrinsic::objc_retainAutorelease:
- case Intrinsic::objc_retainAutoreleaseReturnValue:
- case Intrinsic::objc_retainAutoreleasedReturnValue:
- case Intrinsic::objc_retainBlock:
- case Intrinsic::objc_storeStrong:
- case Intrinsic::objc_storeWeak:
- case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue:
- case Intrinsic::objc_retainedObject:
- case Intrinsic::objc_unretainedObject:
- case Intrinsic::objc_unretainedPointer:
- case Intrinsic::objc_retain_autorelease:
- case Intrinsic::objc_sync_enter:
- case Intrinsic::objc_sync_exit:
- return true;
- default:
- return false;
- }
- }
- //===----------------------------------------------------------------------===//
- /// DbgVariableIntrinsic - This is the common base class for debug info
- /// intrinsics for variables.
- ///
- iterator_range<DbgVariableIntrinsic::location_op_iterator>
- DbgVariableIntrinsic::location_ops() const {
- auto *MD = getRawLocation();
- assert(MD && "First operand of DbgVariableIntrinsic should be non-null.");
- // If operand is ValueAsMetadata, return a range over just that operand.
- if (auto *VAM = dyn_cast<ValueAsMetadata>(MD)) {
- return {location_op_iterator(VAM), location_op_iterator(VAM + 1)};
- }
- // If operand is DIArgList, return a range over its args.
- if (auto *AL = dyn_cast<DIArgList>(MD))
- return {location_op_iterator(AL->args_begin()),
- location_op_iterator(AL->args_end())};
- // Operand must be an empty metadata tuple, so return empty iterator.
- return {location_op_iterator(static_cast<ValueAsMetadata *>(nullptr)),
- location_op_iterator(static_cast<ValueAsMetadata *>(nullptr))};
- }
- Value *DbgVariableIntrinsic::getVariableLocationOp(unsigned OpIdx) const {
- auto *MD = getRawLocation();
- assert(MD && "First operand of DbgVariableIntrinsic should be non-null.");
- if (auto *AL = dyn_cast<DIArgList>(MD))
- return AL->getArgs()[OpIdx]->getValue();
- if (isa<MDNode>(MD))
- return nullptr;
- assert(
- isa<ValueAsMetadata>(MD) &&
- "Attempted to get location operand from DbgVariableIntrinsic with none.");
- auto *V = cast<ValueAsMetadata>(MD);
- assert(OpIdx == 0 && "Operand Index must be 0 for a debug intrinsic with a "
- "single location operand.");
- return V->getValue();
- }
- static ValueAsMetadata *getAsMetadata(Value *V) {
- return isa<MetadataAsValue>(V) ? dyn_cast<ValueAsMetadata>(
- cast<MetadataAsValue>(V)->getMetadata())
- : ValueAsMetadata::get(V);
- }
- void DbgVariableIntrinsic::replaceVariableLocationOp(Value *OldValue,
- Value *NewValue) {
- // If OldValue is used as the address part of a dbg.assign intrinsic replace
- // it with NewValue and return true.
- auto ReplaceDbgAssignAddress = [this, OldValue, NewValue]() -> bool {
- auto *DAI = dyn_cast<DbgAssignIntrinsic>(this);
- if (!DAI || OldValue != DAI->getAddress())
- return false;
- DAI->setAddress(NewValue);
- return true;
- };
- bool DbgAssignAddrReplaced = ReplaceDbgAssignAddress();
- (void)DbgAssignAddrReplaced;
- assert(NewValue && "Values must be non-null");
- auto Locations = location_ops();
- auto OldIt = find(Locations, OldValue);
- assert((OldIt != Locations.end() || DbgAssignAddrReplaced) &&
- "OldValue must be a current location");
- if (!hasArgList()) {
- // Additional check necessary to avoid unconditionally replacing this
- // operand when a dbg.assign address is replaced (DbgAssignAddrReplaced is
- // true).
- if (OldValue != getVariableLocationOp(0))
- return;
- Value *NewOperand = isa<MetadataAsValue>(NewValue)
- ? NewValue
- : MetadataAsValue::get(
- getContext(), ValueAsMetadata::get(NewValue));
- return setArgOperand(0, NewOperand);
- }
- SmallVector<ValueAsMetadata *, 4> MDs;
- ValueAsMetadata *NewOperand = getAsMetadata(NewValue);
- for (auto *VMD : Locations)
- MDs.push_back(VMD == *OldIt ? NewOperand : getAsMetadata(VMD));
- setArgOperand(
- 0, MetadataAsValue::get(getContext(), DIArgList::get(getContext(), MDs)));
- }
- void DbgVariableIntrinsic::replaceVariableLocationOp(unsigned OpIdx,
- Value *NewValue) {
- assert(OpIdx < getNumVariableLocationOps() && "Invalid Operand Index");
- if (!hasArgList()) {
- Value *NewOperand = isa<MetadataAsValue>(NewValue)
- ? NewValue
- : MetadataAsValue::get(
- getContext(), ValueAsMetadata::get(NewValue));
- return setArgOperand(0, NewOperand);
- }
- SmallVector<ValueAsMetadata *, 4> MDs;
- ValueAsMetadata *NewOperand = getAsMetadata(NewValue);
- for (unsigned Idx = 0; Idx < getNumVariableLocationOps(); ++Idx)
- MDs.push_back(Idx == OpIdx ? NewOperand
- : getAsMetadata(getVariableLocationOp(Idx)));
- setArgOperand(
- 0, MetadataAsValue::get(getContext(), DIArgList::get(getContext(), MDs)));
- }
- void DbgVariableIntrinsic::addVariableLocationOps(ArrayRef<Value *> NewValues,
- DIExpression *NewExpr) {
- assert(NewExpr->hasAllLocationOps(getNumVariableLocationOps() +
- NewValues.size()) &&
- "NewExpr for debug variable intrinsic does not reference every "
- "location operand.");
- assert(!is_contained(NewValues, nullptr) && "New values must be non-null");
- setArgOperand(2, MetadataAsValue::get(getContext(), NewExpr));
- SmallVector<ValueAsMetadata *, 4> MDs;
- for (auto *VMD : location_ops())
- MDs.push_back(getAsMetadata(VMD));
- for (auto *VMD : NewValues)
- MDs.push_back(getAsMetadata(VMD));
- setArgOperand(
- 0, MetadataAsValue::get(getContext(), DIArgList::get(getContext(), MDs)));
- }
- std::optional<uint64_t> DbgVariableIntrinsic::getFragmentSizeInBits() const {
- if (auto Fragment = getExpression()->getFragmentInfo())
- return Fragment->SizeInBits;
- return getVariable()->getSizeInBits();
- }
- Value *DbgAssignIntrinsic::getAddress() const {
- auto *MD = getRawAddress();
- if (auto *V = dyn_cast<ValueAsMetadata>(MD))
- return V->getValue();
- // When the value goes to null, it gets replaced by an empty MDNode.
- assert(!cast<MDNode>(MD)->getNumOperands() && "Expected an empty MDNode");
- return nullptr;
- }
- void DbgAssignIntrinsic::setAssignId(DIAssignID *New) {
- setOperand(OpAssignID, MetadataAsValue::get(getContext(), New));
- }
- void DbgAssignIntrinsic::setAddress(Value *V) {
- assert(V->getType()->isPointerTy() &&
- "Destination Component must be a pointer type");
- setOperand(OpAddress,
- MetadataAsValue::get(getContext(), ValueAsMetadata::get(V)));
- }
- void DbgAssignIntrinsic::setKillAddress() {
- if (isKillAddress())
- return;
- setAddress(UndefValue::get(getAddress()->getType()));
- }
- bool DbgAssignIntrinsic::isKillAddress() const {
- Value *Addr = getAddress();
- return !Addr || isa<UndefValue>(Addr);
- }
- void DbgAssignIntrinsic::setValue(Value *V) {
- setOperand(OpValue,
- MetadataAsValue::get(getContext(), ValueAsMetadata::get(V)));
- }
- int llvm::Intrinsic::lookupLLVMIntrinsicByName(ArrayRef<const char *> NameTable,
- StringRef Name) {
- assert(Name.startswith("llvm."));
- // Do successive binary searches of the dotted name components. For
- // "llvm.gc.experimental.statepoint.p1i8.p1i32", we will find the range of
- // intrinsics starting with "llvm.gc", then "llvm.gc.experimental", then
- // "llvm.gc.experimental.statepoint", and then we will stop as the range is
- // size 1. During the search, we can skip the prefix that we already know is
- // identical. By using strncmp we consider names with differing suffixes to
- // be part of the equal range.
- size_t CmpEnd = 4; // Skip the "llvm" component.
- const char *const *Low = NameTable.begin();
- const char *const *High = NameTable.end();
- const char *const *LastLow = Low;
- while (CmpEnd < Name.size() && High - Low > 0) {
- size_t CmpStart = CmpEnd;
- CmpEnd = Name.find('.', CmpStart + 1);
- CmpEnd = CmpEnd == StringRef::npos ? Name.size() : CmpEnd;
- auto Cmp = [CmpStart, CmpEnd](const char *LHS, const char *RHS) {
- return strncmp(LHS + CmpStart, RHS + CmpStart, CmpEnd - CmpStart) < 0;
- };
- LastLow = Low;
- std::tie(Low, High) = std::equal_range(Low, High, Name.data(), Cmp);
- }
- if (High - Low > 0)
- LastLow = Low;
- if (LastLow == NameTable.end())
- return -1;
- StringRef NameFound = *LastLow;
- if (Name == NameFound ||
- (Name.startswith(NameFound) && Name[NameFound.size()] == '.'))
- return LastLow - NameTable.begin();
- return -1;
- }
- ConstantInt *InstrProfInstBase::getNumCounters() const {
- if (InstrProfValueProfileInst::classof(this))
- llvm_unreachable("InstrProfValueProfileInst does not have counters!");
- return cast<ConstantInt>(const_cast<Value *>(getArgOperand(2)));
- }
- ConstantInt *InstrProfInstBase::getIndex() const {
- if (InstrProfValueProfileInst::classof(this))
- llvm_unreachable("Please use InstrProfValueProfileInst::getIndex()");
- return cast<ConstantInt>(const_cast<Value *>(getArgOperand(3)));
- }
- Value *InstrProfIncrementInst::getStep() const {
- if (InstrProfIncrementInstStep::classof(this)) {
- return const_cast<Value *>(getArgOperand(4));
- }
- const Module *M = getModule();
- LLVMContext &Context = M->getContext();
- return ConstantInt::get(Type::getInt64Ty(Context), 1);
- }
- std::optional<RoundingMode> ConstrainedFPIntrinsic::getRoundingMode() const {
- unsigned NumOperands = arg_size();
- Metadata *MD = nullptr;
- auto *MAV = dyn_cast<MetadataAsValue>(getArgOperand(NumOperands - 2));
- if (MAV)
- MD = MAV->getMetadata();
- if (!MD || !isa<MDString>(MD))
- return std::nullopt;
- return convertStrToRoundingMode(cast<MDString>(MD)->getString());
- }
- std::optional<fp::ExceptionBehavior>
- ConstrainedFPIntrinsic::getExceptionBehavior() const {
- unsigned NumOperands = arg_size();
- Metadata *MD = nullptr;
- auto *MAV = dyn_cast<MetadataAsValue>(getArgOperand(NumOperands - 1));
- if (MAV)
- MD = MAV->getMetadata();
- if (!MD || !isa<MDString>(MD))
- return std::nullopt;
- return convertStrToExceptionBehavior(cast<MDString>(MD)->getString());
- }
- bool ConstrainedFPIntrinsic::isDefaultFPEnvironment() const {
- std::optional<fp::ExceptionBehavior> Except = getExceptionBehavior();
- if (Except) {
- if (*Except != fp::ebIgnore)
- return false;
- }
- std::optional<RoundingMode> Rounding = getRoundingMode();
- if (Rounding) {
- if (*Rounding != RoundingMode::NearestTiesToEven)
- return false;
- }
- return true;
- }
- static FCmpInst::Predicate getFPPredicateFromMD(const Value *Op) {
- Metadata *MD = cast<MetadataAsValue>(Op)->getMetadata();
- if (!MD || !isa<MDString>(MD))
- return FCmpInst::BAD_FCMP_PREDICATE;
- return StringSwitch<FCmpInst::Predicate>(cast<MDString>(MD)->getString())
- .Case("oeq", FCmpInst::FCMP_OEQ)
- .Case("ogt", FCmpInst::FCMP_OGT)
- .Case("oge", FCmpInst::FCMP_OGE)
- .Case("olt", FCmpInst::FCMP_OLT)
- .Case("ole", FCmpInst::FCMP_OLE)
- .Case("one", FCmpInst::FCMP_ONE)
- .Case("ord", FCmpInst::FCMP_ORD)
- .Case("uno", FCmpInst::FCMP_UNO)
- .Case("ueq", FCmpInst::FCMP_UEQ)
- .Case("ugt", FCmpInst::FCMP_UGT)
- .Case("uge", FCmpInst::FCMP_UGE)
- .Case("ult", FCmpInst::FCMP_ULT)
- .Case("ule", FCmpInst::FCMP_ULE)
- .Case("une", FCmpInst::FCMP_UNE)
- .Default(FCmpInst::BAD_FCMP_PREDICATE);
- }
- FCmpInst::Predicate ConstrainedFPCmpIntrinsic::getPredicate() const {
- return getFPPredicateFromMD(getArgOperand(2));
- }
- bool ConstrainedFPIntrinsic::isUnaryOp() const {
- switch (getIntrinsicID()) {
- default:
- return false;
- #define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC) \
- case Intrinsic::INTRINSIC: \
- return NARG == 1;
- #include "llvm/IR/ConstrainedOps.def"
- }
- }
- bool ConstrainedFPIntrinsic::isTernaryOp() const {
- switch (getIntrinsicID()) {
- default:
- return false;
- #define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC) \
- case Intrinsic::INTRINSIC: \
- return NARG == 3;
- #include "llvm/IR/ConstrainedOps.def"
- }
- }
- bool ConstrainedFPIntrinsic::classof(const IntrinsicInst *I) {
- switch (I->getIntrinsicID()) {
- #define INSTRUCTION(NAME, NARGS, ROUND_MODE, INTRINSIC) \
- case Intrinsic::INTRINSIC:
- #include "llvm/IR/ConstrainedOps.def"
- return true;
- default:
- return false;
- }
- }
- ElementCount VPIntrinsic::getStaticVectorLength() const {
- auto GetVectorLengthOfType = [](const Type *T) -> ElementCount {
- const auto *VT = cast<VectorType>(T);
- auto ElemCount = VT->getElementCount();
- return ElemCount;
- };
- Value *VPMask = getMaskParam();
- if (!VPMask) {
- assert((getIntrinsicID() == Intrinsic::vp_merge ||
- getIntrinsicID() == Intrinsic::vp_select) &&
- "Unexpected VP intrinsic without mask operand");
- return GetVectorLengthOfType(getType());
- }
- return GetVectorLengthOfType(VPMask->getType());
- }
- Value *VPIntrinsic::getMaskParam() const {
- if (auto MaskPos = getMaskParamPos(getIntrinsicID()))
- return getArgOperand(*MaskPos);
- return nullptr;
- }
- void VPIntrinsic::setMaskParam(Value *NewMask) {
- auto MaskPos = getMaskParamPos(getIntrinsicID());
- setArgOperand(*MaskPos, NewMask);
- }
- Value *VPIntrinsic::getVectorLengthParam() const {
- if (auto EVLPos = getVectorLengthParamPos(getIntrinsicID()))
- return getArgOperand(*EVLPos);
- return nullptr;
- }
- void VPIntrinsic::setVectorLengthParam(Value *NewEVL) {
- auto EVLPos = getVectorLengthParamPos(getIntrinsicID());
- setArgOperand(*EVLPos, NewEVL);
- }
- std::optional<unsigned>
- VPIntrinsic::getMaskParamPos(Intrinsic::ID IntrinsicID) {
- switch (IntrinsicID) {
- default:
- return std::nullopt;
- #define BEGIN_REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \
- case Intrinsic::VPID: \
- return MASKPOS;
- #include "llvm/IR/VPIntrinsics.def"
- }
- }
- std::optional<unsigned>
- VPIntrinsic::getVectorLengthParamPos(Intrinsic::ID IntrinsicID) {
- switch (IntrinsicID) {
- default:
- return std::nullopt;
- #define BEGIN_REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \
- case Intrinsic::VPID: \
- return VLENPOS;
- #include "llvm/IR/VPIntrinsics.def"
- }
- }
- /// \return the alignment of the pointer used by this load/store/gather or
- /// scatter.
- MaybeAlign VPIntrinsic::getPointerAlignment() const {
- std::optional<unsigned> PtrParamOpt =
- getMemoryPointerParamPos(getIntrinsicID());
- assert(PtrParamOpt && "no pointer argument!");
- return getParamAlign(*PtrParamOpt);
- }
- /// \return The pointer operand of this load,store, gather or scatter.
- Value *VPIntrinsic::getMemoryPointerParam() const {
- if (auto PtrParamOpt = getMemoryPointerParamPos(getIntrinsicID()))
- return getArgOperand(*PtrParamOpt);
- return nullptr;
- }
- std::optional<unsigned>
- VPIntrinsic::getMemoryPointerParamPos(Intrinsic::ID VPID) {
- switch (VPID) {
- default:
- break;
- #define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:
- #define VP_PROPERTY_MEMOP(POINTERPOS, ...) return POINTERPOS;
- #define END_REGISTER_VP_INTRINSIC(VPID) break;
- #include "llvm/IR/VPIntrinsics.def"
- }
- return std::nullopt;
- }
- /// \return The data (payload) operand of this store or scatter.
- Value *VPIntrinsic::getMemoryDataParam() const {
- auto DataParamOpt = getMemoryDataParamPos(getIntrinsicID());
- if (!DataParamOpt)
- return nullptr;
- return getArgOperand(*DataParamOpt);
- }
- std::optional<unsigned> VPIntrinsic::getMemoryDataParamPos(Intrinsic::ID VPID) {
- switch (VPID) {
- default:
- break;
- #define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:
- #define VP_PROPERTY_MEMOP(POINTERPOS, DATAPOS) return DATAPOS;
- #define END_REGISTER_VP_INTRINSIC(VPID) break;
- #include "llvm/IR/VPIntrinsics.def"
- }
- return std::nullopt;
- }
- bool VPIntrinsic::isVPIntrinsic(Intrinsic::ID ID) {
- switch (ID) {
- default:
- break;
- #define BEGIN_REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \
- case Intrinsic::VPID: \
- return true;
- #include "llvm/IR/VPIntrinsics.def"
- }
- return false;
- }
- // Equivalent non-predicated opcode
- std::optional<unsigned>
- VPIntrinsic::getFunctionalOpcodeForVP(Intrinsic::ID ID) {
- switch (ID) {
- default:
- break;
- #define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:
- #define VP_PROPERTY_FUNCTIONAL_OPC(OPC) return Instruction::OPC;
- #define END_REGISTER_VP_INTRINSIC(VPID) break;
- #include "llvm/IR/VPIntrinsics.def"
- }
- return std::nullopt;
- }
- Intrinsic::ID VPIntrinsic::getForOpcode(unsigned IROPC) {
- switch (IROPC) {
- default:
- break;
- #define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) break;
- #define VP_PROPERTY_FUNCTIONAL_OPC(OPC) case Instruction::OPC:
- #define END_REGISTER_VP_INTRINSIC(VPID) return Intrinsic::VPID;
- #include "llvm/IR/VPIntrinsics.def"
- }
- return Intrinsic::not_intrinsic;
- }
- bool VPIntrinsic::canIgnoreVectorLengthParam() const {
- using namespace PatternMatch;
- ElementCount EC = getStaticVectorLength();
- // No vlen param - no lanes masked-off by it.
- auto *VLParam = getVectorLengthParam();
- if (!VLParam)
- return true;
- // Note that the VP intrinsic causes undefined behavior if the Explicit Vector
- // Length parameter is strictly greater-than the number of vector elements of
- // the operation. This function returns true when this is detected statically
- // in the IR.
- // Check whether "W == vscale * EC.getKnownMinValue()"
- if (EC.isScalable()) {
- // Undig the DL
- const auto *ParMod = this->getModule();
- if (!ParMod)
- return false;
- const auto &DL = ParMod->getDataLayout();
- // Compare vscale patterns
- uint64_t VScaleFactor;
- if (match(VLParam, m_c_Mul(m_ConstantInt(VScaleFactor), m_VScale(DL))))
- return VScaleFactor >= EC.getKnownMinValue();
- return (EC.getKnownMinValue() == 1) && match(VLParam, m_VScale(DL));
- }
- // standard SIMD operation
- const auto *VLConst = dyn_cast<ConstantInt>(VLParam);
- if (!VLConst)
- return false;
- uint64_t VLNum = VLConst->getZExtValue();
- if (VLNum >= EC.getKnownMinValue())
- return true;
- return false;
- }
- Function *VPIntrinsic::getDeclarationForParams(Module *M, Intrinsic::ID VPID,
- Type *ReturnType,
- ArrayRef<Value *> Params) {
- assert(isVPIntrinsic(VPID) && "not a VP intrinsic");
- Function *VPFunc;
- switch (VPID) {
- default: {
- Type *OverloadTy = Params[0]->getType();
- if (VPReductionIntrinsic::isVPReduction(VPID))
- OverloadTy =
- Params[*VPReductionIntrinsic::getVectorParamPos(VPID)]->getType();
- VPFunc = Intrinsic::getDeclaration(M, VPID, OverloadTy);
- break;
- }
- case Intrinsic::vp_trunc:
- case Intrinsic::vp_sext:
- case Intrinsic::vp_zext:
- case Intrinsic::vp_fptoui:
- case Intrinsic::vp_fptosi:
- case Intrinsic::vp_uitofp:
- case Intrinsic::vp_sitofp:
- case Intrinsic::vp_fptrunc:
- case Intrinsic::vp_fpext:
- case Intrinsic::vp_ptrtoint:
- case Intrinsic::vp_inttoptr:
- VPFunc =
- Intrinsic::getDeclaration(M, VPID, {ReturnType, Params[0]->getType()});
- break;
- case Intrinsic::vp_merge:
- case Intrinsic::vp_select:
- VPFunc = Intrinsic::getDeclaration(M, VPID, {Params[1]->getType()});
- break;
- case Intrinsic::vp_load:
- VPFunc = Intrinsic::getDeclaration(
- M, VPID, {ReturnType, Params[0]->getType()});
- break;
- case Intrinsic::experimental_vp_strided_load:
- VPFunc = Intrinsic::getDeclaration(
- M, VPID, {ReturnType, Params[0]->getType(), Params[1]->getType()});
- break;
- case Intrinsic::vp_gather:
- VPFunc = Intrinsic::getDeclaration(
- M, VPID, {ReturnType, Params[0]->getType()});
- break;
- case Intrinsic::vp_store:
- VPFunc = Intrinsic::getDeclaration(
- M, VPID, {Params[0]->getType(), Params[1]->getType()});
- break;
- case Intrinsic::experimental_vp_strided_store:
- VPFunc = Intrinsic::getDeclaration(
- M, VPID,
- {Params[0]->getType(), Params[1]->getType(), Params[2]->getType()});
- break;
- case Intrinsic::vp_scatter:
- VPFunc = Intrinsic::getDeclaration(
- M, VPID, {Params[0]->getType(), Params[1]->getType()});
- break;
- }
- assert(VPFunc && "Could not declare VP intrinsic");
- return VPFunc;
- }
- bool VPReductionIntrinsic::isVPReduction(Intrinsic::ID ID) {
- switch (ID) {
- default:
- break;
- #define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:
- #define VP_PROPERTY_REDUCTION(STARTPOS, ...) return true;
- #define END_REGISTER_VP_INTRINSIC(VPID) break;
- #include "llvm/IR/VPIntrinsics.def"
- }
- return false;
- }
- bool VPCastIntrinsic::isVPCast(Intrinsic::ID ID) {
- switch (ID) {
- default:
- break;
- #define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:
- #define VP_PROPERTY_CASTOP return true;
- #define END_REGISTER_VP_INTRINSIC(VPID) break;
- #include "llvm/IR/VPIntrinsics.def"
- }
- return false;
- }
- bool VPCmpIntrinsic::isVPCmp(Intrinsic::ID ID) {
- switch (ID) {
- default:
- break;
- #define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:
- #define VP_PROPERTY_CMP(CCPOS, ...) return true;
- #define END_REGISTER_VP_INTRINSIC(VPID) break;
- #include "llvm/IR/VPIntrinsics.def"
- }
- return false;
- }
- static ICmpInst::Predicate getIntPredicateFromMD(const Value *Op) {
- Metadata *MD = cast<MetadataAsValue>(Op)->getMetadata();
- if (!MD || !isa<MDString>(MD))
- return ICmpInst::BAD_ICMP_PREDICATE;
- return StringSwitch<ICmpInst::Predicate>(cast<MDString>(MD)->getString())
- .Case("eq", ICmpInst::ICMP_EQ)
- .Case("ne", ICmpInst::ICMP_NE)
- .Case("ugt", ICmpInst::ICMP_UGT)
- .Case("uge", ICmpInst::ICMP_UGE)
- .Case("ult", ICmpInst::ICMP_ULT)
- .Case("ule", ICmpInst::ICMP_ULE)
- .Case("sgt", ICmpInst::ICMP_SGT)
- .Case("sge", ICmpInst::ICMP_SGE)
- .Case("slt", ICmpInst::ICMP_SLT)
- .Case("sle", ICmpInst::ICMP_SLE)
- .Default(ICmpInst::BAD_ICMP_PREDICATE);
- }
- CmpInst::Predicate VPCmpIntrinsic::getPredicate() const {
- bool IsFP = true;
- std::optional<unsigned> CCArgIdx;
- switch (getIntrinsicID()) {
- default:
- break;
- #define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:
- #define VP_PROPERTY_CMP(CCPOS, ISFP) \
- CCArgIdx = CCPOS; \
- IsFP = ISFP; \
- break;
- #define END_REGISTER_VP_INTRINSIC(VPID) break;
- #include "llvm/IR/VPIntrinsics.def"
- }
- assert(CCArgIdx && "Unexpected vector-predicated comparison");
- return IsFP ? getFPPredicateFromMD(getArgOperand(*CCArgIdx))
- : getIntPredicateFromMD(getArgOperand(*CCArgIdx));
- }
- unsigned VPReductionIntrinsic::getVectorParamPos() const {
- return *VPReductionIntrinsic::getVectorParamPos(getIntrinsicID());
- }
- unsigned VPReductionIntrinsic::getStartParamPos() const {
- return *VPReductionIntrinsic::getStartParamPos(getIntrinsicID());
- }
- std::optional<unsigned>
- VPReductionIntrinsic::getVectorParamPos(Intrinsic::ID ID) {
- switch (ID) {
- #define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:
- #define VP_PROPERTY_REDUCTION(STARTPOS, VECTORPOS) return VECTORPOS;
- #define END_REGISTER_VP_INTRINSIC(VPID) break;
- #include "llvm/IR/VPIntrinsics.def"
- default:
- break;
- }
- return std::nullopt;
- }
- std::optional<unsigned>
- VPReductionIntrinsic::getStartParamPos(Intrinsic::ID ID) {
- switch (ID) {
- #define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:
- #define VP_PROPERTY_REDUCTION(STARTPOS, VECTORPOS) return STARTPOS;
- #define END_REGISTER_VP_INTRINSIC(VPID) break;
- #include "llvm/IR/VPIntrinsics.def"
- default:
- break;
- }
- return std::nullopt;
- }
- Instruction::BinaryOps BinaryOpIntrinsic::getBinaryOp() const {
- switch (getIntrinsicID()) {
- case Intrinsic::uadd_with_overflow:
- case Intrinsic::sadd_with_overflow:
- case Intrinsic::uadd_sat:
- case Intrinsic::sadd_sat:
- return Instruction::Add;
- case Intrinsic::usub_with_overflow:
- case Intrinsic::ssub_with_overflow:
- case Intrinsic::usub_sat:
- case Intrinsic::ssub_sat:
- return Instruction::Sub;
- case Intrinsic::umul_with_overflow:
- case Intrinsic::smul_with_overflow:
- return Instruction::Mul;
- default:
- llvm_unreachable("Invalid intrinsic");
- }
- }
- bool BinaryOpIntrinsic::isSigned() const {
- switch (getIntrinsicID()) {
- case Intrinsic::sadd_with_overflow:
- case Intrinsic::ssub_with_overflow:
- case Intrinsic::smul_with_overflow:
- case Intrinsic::sadd_sat:
- case Intrinsic::ssub_sat:
- return true;
- default:
- return false;
- }
- }
- unsigned BinaryOpIntrinsic::getNoWrapKind() const {
- if (isSigned())
- return OverflowingBinaryOperator::NoSignedWrap;
- else
- return OverflowingBinaryOperator::NoUnsignedWrap;
- }
- const Value *GCProjectionInst::getStatepoint() const {
- const Value *Token = getArgOperand(0);
- if (isa<UndefValue>(Token))
- return Token;
- // This takes care both of relocates for call statepoints and relocates
- // on normal path of invoke statepoint.
- if (!isa<LandingPadInst>(Token))
- return cast<GCStatepointInst>(Token);
- // This relocate is on exceptional path of an invoke statepoint
- const BasicBlock *InvokeBB =
- cast<Instruction>(Token)->getParent()->getUniquePredecessor();
- assert(InvokeBB && "safepoints should have unique landingpads");
- assert(InvokeBB->getTerminator() &&
- "safepoint block should be well formed");
- return cast<GCStatepointInst>(InvokeBB->getTerminator());
- }
- Value *GCRelocateInst::getBasePtr() const {
- auto Statepoint = getStatepoint();
- if (isa<UndefValue>(Statepoint))
- return UndefValue::get(Statepoint->getType());
- auto *GCInst = cast<GCStatepointInst>(Statepoint);
- if (auto Opt = GCInst->getOperandBundle(LLVMContext::OB_gc_live))
- return *(Opt->Inputs.begin() + getBasePtrIndex());
- return *(GCInst->arg_begin() + getBasePtrIndex());
- }
- Value *GCRelocateInst::getDerivedPtr() const {
- auto *Statepoint = getStatepoint();
- if (isa<UndefValue>(Statepoint))
- return UndefValue::get(Statepoint->getType());
- auto *GCInst = cast<GCStatepointInst>(Statepoint);
- if (auto Opt = GCInst->getOperandBundle(LLVMContext::OB_gc_live))
- return *(Opt->Inputs.begin() + getDerivedPtrIndex());
- return *(GCInst->arg_begin() + getDerivedPtrIndex());
- }
|