Files
RedBear-OS/local/recipes/dev/libclc/source/llvm/lib/IR/IntrinsicInst.cpp
T
vasilito cb424d7448 build: static patch-sanity linter (shift-left the malformed-patch class)
verify-patch-sanity.py validates every active recipe .patch has internally-
consistent hunk line counts — catching the 'malformed patch at line N' failure
at commit/CI/preflight time instead of hours into a cook. This cycle hit that
class three times (qtwaylandscanner, sddm, xwayland), each only discovered when
cookbook tried to apply the patch.

Running it across the repo found 29 latent malformed patches (validated against
GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22').
They were harmless only because they sit in vendored recipes (baked, not re-
applied) — but would fail on any version-bump re-derivation. --fix recounts the
hunk headers (body untouched) and repaired all 29.

Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test
(test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats
(empty placeholders, bare-@@ git hunks).
2026-08-01 05:13:02 +03:00

916 lines
30 KiB
C++

//===-- 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<location_op_iterator> RawLocationWrapper::location_ops() const {
Metadata *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))};
}
iterator_range<location_op_iterator>
DbgVariableIntrinsic::location_ops() const {
return getWrappedLocation().location_ops();
}
Value *DbgVariableIntrinsic::getVariableLocationOp(unsigned OpIdx) const {
return getWrappedLocation().getVariableLocationOp(OpIdx);
}
Value *RawLocationWrapper::getVariableLocationOp(unsigned OpIdx) const {
Metadata *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,
bool AllowEmpty) {
// 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);
if (OldIt == Locations.end()) {
if (AllowEmpty || DbgAssignAddrReplaced)
return;
assert(DbgAssignAddrReplaced &&
"OldValue must be dbg.assign addr if unused in DIArgList");
return;
}
assert(OldIt != Locations.end() && "OldValue must be a current location");
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 (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) {
setOperand(OpAddress,
MetadataAsValue::get(getContext(), ValueAsMetadata::get(V)));
}
void DbgAssignIntrinsic::setKillAddress() {
if (isKillAddress())
return;
setAddress(PoisonValue::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)));
}
ConstantInt *InstrProfCntrInstBase::getNumCounters() const {
if (InstrProfValueProfileInst::classof(this))
llvm_unreachable("InstrProfValueProfileInst does not have counters!");
return cast<ConstantInt>(getArgOperand(2));
}
ConstantInt *InstrProfCntrInstBase::getIndex() const {
if (InstrProfValueProfileInst::classof(this))
llvm_unreachable("Please use InstrProfValueProfileInst::getIndex()");
return cast<ConstantInt>(getArgOperand(3));
}
void InstrProfCntrInstBase::setIndex(uint32_t Idx) {
assert(isa<InstrProfCntrInstBase>(this));
setArgOperand(3, ConstantInt::get(Type::getInt32Ty(getContext()), Idx));
}
Value *InstrProfIncrementInst::getStep() const {
if (InstrProfIncrementInstStep::classof(this)) {
return getArgOperand(4);
}
const Module *M = getModule();
LLVMContext &Context = M->getContext();
return ConstantInt::get(Type::getInt64Ty(Context), 1);
}
Value *InstrProfCallsite::getCallee() const {
if (isa<InstrProfCallsite>(this))
return getArgOperand(4);
return nullptr;
}
void InstrProfCallsite::setCallee(Value *Callee) {
assert(isa<InstrProfCallsite>(this));
setArgOperand(4, Callee);
}
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));
}
unsigned ConstrainedFPIntrinsic::getNonMetadataArgCount() const {
// All constrained fp intrinsics have "fpexcept" metadata.
unsigned NumArgs = arg_size() - 1;
// Some intrinsics have "round" metadata.
if (Intrinsic::hasConstrainedFPRoundingModeOperand(getIntrinsicID()))
NumArgs -= 1;
// Compare intrinsics take their predicate as metadata.
if (isa<ConstrainedFPCmpIntrinsic>(this))
NumArgs -= 1;
return NumArgs;
}
bool ConstrainedFPIntrinsic::classof(const IntrinsicInst *I) {
return Intrinsic::isConstrainedFPIntrinsic(I->getIntrinsicID());
}
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:
return std::nullopt;
case Intrinsic::vp_store:
case Intrinsic::vp_scatter:
case Intrinsic::experimental_vp_strided_store:
return 1;
case Intrinsic::vp_load:
case Intrinsic::vp_gather:
case Intrinsic::experimental_vp_strided_load:
return 0;
}
}
/// \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:
return std::nullopt;
case Intrinsic::vp_store:
case Intrinsic::vp_scatter:
case Intrinsic::experimental_vp_strided_store:
return 0;
}
}
constexpr bool 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;
}
bool VPIntrinsic::isVPIntrinsic(Intrinsic::ID ID) {
return ::isVPIntrinsic(ID);
}
// Equivalent non-predicated opcode
constexpr static std::optional<unsigned>
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;
}
std::optional<unsigned>
VPIntrinsic::getFunctionalOpcodeForVP(Intrinsic::ID ID) {
return ::getFunctionalOpcodeForVP(ID);
}
// Equivalent non-predicated intrinsic ID
constexpr static std::optional<Intrinsic::ID>
getFunctionalIntrinsicIDForVP(Intrinsic::ID ID) {
switch (ID) {
default:
break;
#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:
#define VP_PROPERTY_FUNCTIONAL_INTRINSIC(INTRIN) return Intrinsic::INTRIN;
#define END_REGISTER_VP_INTRINSIC(VPID) break;
#include "llvm/IR/VPIntrinsics.def"
}
return std::nullopt;
}
std::optional<Intrinsic::ID>
VPIntrinsic::getFunctionalIntrinsicIDForVP(Intrinsic::ID ID) {
return ::getFunctionalIntrinsicIDForVP(ID);
}
constexpr static bool doesVPHaveNoFunctionalEquivalent(Intrinsic::ID ID) {
switch (ID) {
default:
break;
#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:
#define VP_PROPERTY_NO_FUNCTIONAL return true;
#define END_REGISTER_VP_INTRINSIC(VPID) break;
#include "llvm/IR/VPIntrinsics.def"
}
return false;
}
// All VP intrinsics should have an equivalent non-VP opcode or intrinsic
// defined, or be marked that they don't have one.
#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) \
static_assert(doesVPHaveNoFunctionalEquivalent(Intrinsic::VPID) || \
getFunctionalOpcodeForVP(Intrinsic::VPID) || \
getFunctionalIntrinsicIDForVP(Intrinsic::VPID));
#include "llvm/IR/VPIntrinsics.def"
// Equivalent non-predicated constrained intrinsic
std::optional<Intrinsic::ID>
VPIntrinsic::getConstrainedIntrinsicIDForVP(Intrinsic::ID ID) {
switch (ID) {
default:
break;
#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:
#define VP_PROPERTY_CONSTRAINEDFP(CID) return Intrinsic::CID;
#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;
}
constexpr static Intrinsic::ID getForIntrinsic(Intrinsic::ID Id) {
if (::isVPIntrinsic(Id))
return Id;
switch (Id) {
default:
break;
#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) break;
#define VP_PROPERTY_FUNCTIONAL_INTRINSIC(INTRIN) case Intrinsic::INTRIN:
#define END_REGISTER_VP_INTRINSIC(VPID) return Intrinsic::VPID;
#include "llvm/IR/VPIntrinsics.def"
}
return Intrinsic::not_intrinsic;
}
Intrinsic::ID VPIntrinsic::getForIntrinsic(Intrinsic::ID Id) {
return ::getForIntrinsic(Id);
}
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()) {
// Compare vscale patterns
uint64_t VScaleFactor;
if (match(VLParam, m_Mul(m_VScale(), m_ConstantInt(VScaleFactor))))
return VScaleFactor >= EC.getKnownMinValue();
return (EC.getKnownMinValue() == 1) && match(VLParam, m_VScale());
}
// 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::getOrInsertDeclarationForParams(
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::getOrInsertDeclaration(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:
case Intrinsic::vp_lrint:
case Intrinsic::vp_llrint:
case Intrinsic::vp_cttz_elts:
VPFunc = Intrinsic::getOrInsertDeclaration(
M, VPID, {ReturnType, Params[0]->getType()});
break;
case Intrinsic::vp_is_fpclass:
VPFunc = Intrinsic::getOrInsertDeclaration(M, VPID, {Params[0]->getType()});
break;
case Intrinsic::vp_merge:
case Intrinsic::vp_select:
VPFunc = Intrinsic::getOrInsertDeclaration(M, VPID, {Params[1]->getType()});
break;
case Intrinsic::vp_load:
VPFunc = Intrinsic::getOrInsertDeclaration(
M, VPID, {ReturnType, Params[0]->getType()});
break;
case Intrinsic::experimental_vp_strided_load:
VPFunc = Intrinsic::getOrInsertDeclaration(
M, VPID, {ReturnType, Params[0]->getType(), Params[1]->getType()});
break;
case Intrinsic::vp_gather:
VPFunc = Intrinsic::getOrInsertDeclaration(
M, VPID, {ReturnType, Params[0]->getType()});
break;
case Intrinsic::vp_store:
VPFunc = Intrinsic::getOrInsertDeclaration(
M, VPID, {Params[0]->getType(), Params[1]->getType()});
break;
case Intrinsic::experimental_vp_strided_store:
VPFunc = Intrinsic::getOrInsertDeclaration(
M, VPID,
{Params[0]->getType(), Params[1]->getType(), Params[2]->getType()});
break;
case Intrinsic::vp_scatter:
VPFunc = Intrinsic::getOrInsertDeclaration(
M, VPID, {Params[0]->getType(), Params[1]->getType()});
break;
case Intrinsic::experimental_vp_splat:
VPFunc = Intrinsic::getOrInsertDeclaration(M, VPID, ReturnType);
break;
}
assert(VPFunc && "Could not declare VP intrinsic");
return VPFunc;
}
bool VPReductionIntrinsic::isVPReduction(Intrinsic::ID ID) {
switch (ID) {
case Intrinsic::vp_reduce_add:
case Intrinsic::vp_reduce_mul:
case Intrinsic::vp_reduce_and:
case Intrinsic::vp_reduce_or:
case Intrinsic::vp_reduce_xor:
case Intrinsic::vp_reduce_smax:
case Intrinsic::vp_reduce_smin:
case Intrinsic::vp_reduce_umax:
case Intrinsic::vp_reduce_umin:
case Intrinsic::vp_reduce_fmax:
case Intrinsic::vp_reduce_fmin:
case Intrinsic::vp_reduce_fmaximum:
case Intrinsic::vp_reduce_fminimum:
case Intrinsic::vp_reduce_fadd:
case Intrinsic::vp_reduce_fmul:
return true;
default:
return false;
}
}
bool VPCastIntrinsic::isVPCast(Intrinsic::ID ID) {
// All of the vp.casts correspond to instructions
if (std::optional<unsigned> Opc = getFunctionalOpcodeForVP(ID))
return Instruction::isCast(*Opc);
return false;
}
bool VPCmpIntrinsic::isVPCmp(Intrinsic::ID ID) {
switch (ID) {
default:
return false;
case Intrinsic::vp_fcmp:
case Intrinsic::vp_icmp:
return true;
}
}
bool VPBinOpIntrinsic::isVPBinOp(Intrinsic::ID ID) {
switch (ID) {
default:
break;
#define BEGIN_REGISTER_VP_INTRINSIC(VPID, ...) case Intrinsic::VPID:
#define VP_PROPERTY_BINARYOP 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 {
assert(isVPCmp(getIntrinsicID()));
return getIntrinsicID() == Intrinsic::vp_fcmp
? getFPPredicateFromMD(getArgOperand(2))
: getIntPredicateFromMD(getArgOperand(2));
}
unsigned VPReductionIntrinsic::getVectorParamPos() const {
return *VPReductionIntrinsic::getVectorParamPos(getIntrinsicID());
}
unsigned VPReductionIntrinsic::getStartParamPos() const {
return *VPReductionIntrinsic::getStartParamPos(getIntrinsicID());
}
std::optional<unsigned>
VPReductionIntrinsic::getVectorParamPos(Intrinsic::ID ID) {
if (isVPReduction(ID))
return 1;
return std::nullopt;
}
std::optional<unsigned>
VPReductionIntrinsic::getStartParamPos(Intrinsic::ID ID) {
if (isVPReduction(ID))
return 0;
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;
// Treat none token as if it was undef here
if (isa<ConstantTokenNone>(Token))
return UndefValue::get(Token->getType());
// 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());
}
ConvergenceControlInst *ConvergenceControlInst::CreateAnchor(BasicBlock &BB) {
Module *M = BB.getModule();
Function *Fn = Intrinsic::getOrInsertDeclaration(
M, llvm::Intrinsic::experimental_convergence_anchor);
auto *Call = CallInst::Create(Fn, "", BB.getFirstInsertionPt());
return cast<ConvergenceControlInst>(Call);
}
ConvergenceControlInst *ConvergenceControlInst::CreateEntry(BasicBlock &BB) {
Module *M = BB.getModule();
Function *Fn = Intrinsic::getOrInsertDeclaration(
M, llvm::Intrinsic::experimental_convergence_entry);
auto *Call = CallInst::Create(Fn, "", BB.getFirstInsertionPt());
return cast<ConvergenceControlInst>(Call);
}
ConvergenceControlInst *
ConvergenceControlInst::CreateLoop(BasicBlock &BB,
ConvergenceControlInst *ParentToken) {
Module *M = BB.getModule();
Function *Fn = Intrinsic::getOrInsertDeclaration(
M, llvm::Intrinsic::experimental_convergence_loop);
llvm::Value *BundleArgs[] = {ParentToken};
llvm::OperandBundleDef OB("convergencectrl", BundleArgs);
auto *Call = CallInst::Create(Fn, {}, {OB}, "", BB.getFirstInsertionPt());
return cast<ConvergenceControlInst>(Call);
}