aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/IR/IntrinsicInst.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/IR/IntrinsicInst.cpp')
-rw-r--r--llvm/lib/IR/IntrinsicInst.cpp287
1 files changed, 257 insertions, 30 deletions
diff --git a/llvm/lib/IR/IntrinsicInst.cpp b/llvm/lib/IR/IntrinsicInst.cpp
index 3d1ea2853591..19942fa187fd 100644
--- a/llvm/lib/IR/IntrinsicInst.cpp
+++ b/llvm/lib/IR/IntrinsicInst.cpp
@@ -1,4 +1,4 @@
-//===-- InstrinsicInst.cpp - Intrinsic Instruction Wrappers ---------------===//
+//===-- 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.
@@ -29,6 +29,7 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/PatternMatch.h"
+#include "llvm/IR/Statepoint.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -38,18 +39,100 @@ using namespace llvm;
/// intrinsics for variables.
///
-Value *DbgVariableIntrinsic::getVariableLocation(bool AllowNullOp) const {
- Value *Op = getArgOperand(0);
- if (AllowNullOp && !Op)
+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();
+}
- auto *MD = cast<MetadataAsValue>(Op)->getMetadata();
- if (auto *V = dyn_cast<ValueAsMetadata>(MD))
- return V->getValue();
+static ValueAsMetadata *getAsMetadata(Value *V) {
+ return isa<MetadataAsValue>(V) ? dyn_cast<ValueAsMetadata>(
+ cast<MetadataAsValue>(V)->getMetadata())
+ : ValueAsMetadata::get(V);
+}
- // 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 DbgVariableIntrinsic::replaceVariableLocationOp(Value *OldValue,
+ Value *NewValue) {
+ assert(NewValue && "Values must be non-null");
+ auto Locations = location_ops();
+ auto OldIt = find(Locations, OldValue);
+ 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)));
}
Optional<uint64_t> DbgVariableIntrinsic::getFragmentSizeInBits() const {
@@ -106,8 +189,10 @@ Value *InstrProfIncrementInst::getStep() const {
Optional<RoundingMode> ConstrainedFPIntrinsic::getRoundingMode() const {
unsigned NumOperands = getNumArgOperands();
- Metadata *MD =
- cast<MetadataAsValue>(getArgOperand(NumOperands - 2))->getMetadata();
+ Metadata *MD = nullptr;
+ auto *MAV = dyn_cast<MetadataAsValue>(getArgOperand(NumOperands - 2));
+ if (MAV)
+ MD = MAV->getMetadata();
if (!MD || !isa<MDString>(MD))
return None;
return StrToRoundingMode(cast<MDString>(MD)->getString());
@@ -116,13 +201,31 @@ Optional<RoundingMode> ConstrainedFPIntrinsic::getRoundingMode() const {
Optional<fp::ExceptionBehavior>
ConstrainedFPIntrinsic::getExceptionBehavior() const {
unsigned NumOperands = getNumArgOperands();
- Metadata *MD =
- cast<MetadataAsValue>(getArgOperand(NumOperands - 1))->getMetadata();
+ Metadata *MD = nullptr;
+ auto *MAV = dyn_cast<MetadataAsValue>(getArgOperand(NumOperands - 1));
+ if (MAV)
+ MD = MAV->getMetadata();
if (!MD || !isa<MDString>(MD))
return None;
return StrToExceptionBehavior(cast<MDString>(MD)->getString());
}
+bool ConstrainedFPIntrinsic::isDefaultFPEnvironment() const {
+ Optional<fp::ExceptionBehavior> Except = getExceptionBehavior();
+ if (Except) {
+ if (Except.getValue() != fp::ebIgnore)
+ return false;
+ }
+
+ Optional<RoundingMode> Rounding = getRoundingMode();
+ if (Rounding) {
+ if (Rounding.getValue() != RoundingMode::NearestTiesToEven)
+ return false;
+ }
+
+ return true;
+}
+
FCmpInst::Predicate ConstrainedFPCmpIntrinsic::getPredicate() const {
Metadata *MD = cast<MetadataAsValue>(getArgOperand(2))->getMetadata();
if (!MD || !isa<MDString>(MD))
@@ -180,30 +283,39 @@ bool ConstrainedFPIntrinsic::classof(const IntrinsicInst *I) {
ElementCount VPIntrinsic::getStaticVectorLength() const {
auto GetVectorLengthOfType = [](const Type *T) -> ElementCount {
- auto VT = cast<VectorType>(T);
+ const auto *VT = cast<VectorType>(T);
auto ElemCount = VT->getElementCount();
return ElemCount;
};
- auto VPMask = getMaskParam();
+ Value *VPMask = getMaskParam();
+ assert(VPMask && "No mask param?");
return GetVectorLengthOfType(VPMask->getType());
}
Value *VPIntrinsic::getMaskParam() const {
- auto maskPos = GetMaskParamPos(getIntrinsicID());
- if (maskPos)
- return getArgOperand(maskPos.getValue());
+ if (auto MaskPos = getMaskParamPos(getIntrinsicID()))
+ return getArgOperand(MaskPos.getValue());
return nullptr;
}
+void VPIntrinsic::setMaskParam(Value *NewMask) {
+ auto MaskPos = getMaskParamPos(getIntrinsicID());
+ setArgOperand(*MaskPos, NewMask);
+}
+
Value *VPIntrinsic::getVectorLengthParam() const {
- auto vlenPos = GetVectorLengthParamPos(getIntrinsicID());
- if (vlenPos)
- return getArgOperand(vlenPos.getValue());
+ if (auto EVLPos = getVectorLengthParamPos(getIntrinsicID()))
+ return getArgOperand(EVLPos.getValue());
return nullptr;
}
-Optional<int> VPIntrinsic::GetMaskParamPos(Intrinsic::ID IntrinsicID) {
+void VPIntrinsic::setVectorLengthParam(Value *NewEVL) {
+ auto EVLPos = getVectorLengthParamPos(getIntrinsicID());
+ setArgOperand(*EVLPos, NewEVL);
+}
+
+Optional<unsigned> VPIntrinsic::getMaskParamPos(Intrinsic::ID IntrinsicID) {
switch (IntrinsicID) {
default:
return None;
@@ -215,7 +327,8 @@ Optional<int> VPIntrinsic::GetMaskParamPos(Intrinsic::ID IntrinsicID) {
}
}
-Optional<int> VPIntrinsic::GetVectorLengthParamPos(Intrinsic::ID IntrinsicID) {
+Optional<unsigned>
+VPIntrinsic::getVectorLengthParamPos(Intrinsic::ID IntrinsicID) {
switch (IntrinsicID) {
default:
return None;
@@ -227,7 +340,54 @@ Optional<int> VPIntrinsic::GetVectorLengthParamPos(Intrinsic::ID IntrinsicID) {
}
}
-bool VPIntrinsic::IsVPIntrinsic(Intrinsic::ID ID) {
+/// \return the alignment of the pointer used by this load/store/gather or
+/// scatter.
+MaybeAlign VPIntrinsic::getPointerAlignment() const {
+ Optional<unsigned> PtrParamOpt = getMemoryPointerParamPos(getIntrinsicID());
+ assert(PtrParamOpt.hasValue() && "no pointer argument!");
+ return getParamAlign(PtrParamOpt.getValue());
+}
+
+/// \return The pointer operand of this load,store, gather or scatter.
+Value *VPIntrinsic::getMemoryPointerParam() const {
+ if (auto PtrParamOpt = getMemoryPointerParamPos(getIntrinsicID()))
+ return getArgOperand(PtrParamOpt.getValue());
+ return nullptr;
+}
+
+Optional<unsigned> VPIntrinsic::getMemoryPointerParamPos(Intrinsic::ID VPID) {
+ switch (VPID) {
+ default:
+ return None;
+
+#define HANDLE_VP_IS_MEMOP(VPID, POINTERPOS, DATAPOS) \
+ case Intrinsic::VPID: \
+ return POINTERPOS;
+#include "llvm/IR/VPIntrinsics.def"
+ }
+}
+
+/// \return The data (payload) operand of this store or scatter.
+Value *VPIntrinsic::getMemoryDataParam() const {
+ auto DataParamOpt = getMemoryDataParamPos(getIntrinsicID());
+ if (!DataParamOpt.hasValue())
+ return nullptr;
+ return getArgOperand(DataParamOpt.getValue());
+}
+
+Optional<unsigned> VPIntrinsic::getMemoryDataParamPos(Intrinsic::ID VPID) {
+ switch (VPID) {
+ default:
+ return None;
+
+#define HANDLE_VP_IS_MEMOP(VPID, POINTERPOS, DATAPOS) \
+ case Intrinsic::VPID: \
+ return DATAPOS;
+#include "llvm/IR/VPIntrinsics.def"
+ }
+}
+
+bool VPIntrinsic::isVPIntrinsic(Intrinsic::ID ID) {
switch (ID) {
default:
return false;
@@ -241,8 +401,8 @@ bool VPIntrinsic::IsVPIntrinsic(Intrinsic::ID ID) {
}
// Equivalent non-predicated opcode
-unsigned VPIntrinsic::GetFunctionalOpcodeForVP(Intrinsic::ID ID) {
- unsigned FunctionalOC = Instruction::Call;
+Optional<unsigned> VPIntrinsic::getFunctionalOpcodeForVP(Intrinsic::ID ID) {
+ Optional<unsigned> FunctionalOC;
switch (ID) {
default:
break;
@@ -255,7 +415,7 @@ unsigned VPIntrinsic::GetFunctionalOpcodeForVP(Intrinsic::ID ID) {
return FunctionalOC;
}
-Intrinsic::ID VPIntrinsic::GetForOpcode(unsigned IROPC) {
+Intrinsic::ID VPIntrinsic::getForOpcode(unsigned IROPC) {
switch (IROPC) {
default:
return Intrinsic::not_intrinsic;
@@ -284,7 +444,7 @@ bool VPIntrinsic::canIgnoreVectorLengthParam() const {
// Check whether "W == vscale * EC.getKnownMinValue()"
if (EC.isScalable()) {
// Undig the DL
- auto ParMod = this->getModule();
+ const auto *ParMod = this->getModule();
if (!ParMod)
return false;
const auto &DL = ParMod->getDataLayout();
@@ -297,7 +457,7 @@ bool VPIntrinsic::canIgnoreVectorLengthParam() const {
}
// standard SIMD operation
- auto VLConst = dyn_cast<ConstantInt>(VLParam);
+ const auto *VLConst = dyn_cast<ConstantInt>(VLParam);
if (!VLConst)
return false;
@@ -308,6 +468,42 @@ bool VPIntrinsic::canIgnoreVectorLengthParam() const {
return false;
}
+Function *VPIntrinsic::getDeclarationForParams(Module *M, Intrinsic::ID VPID,
+ ArrayRef<Value *> Params) {
+ assert(isVPIntrinsic(VPID) && "not a VP intrinsic");
+ Function *VPFunc;
+ switch (VPID) {
+ default:
+ VPFunc = Intrinsic::getDeclaration(M, VPID, Params[0]->getType());
+ break;
+ case Intrinsic::vp_load:
+ VPFunc = Intrinsic::getDeclaration(
+ M, VPID,
+ {Params[0]->getType()->getPointerElementType(), Params[0]->getType()});
+ break;
+ case Intrinsic::vp_gather:
+ VPFunc = Intrinsic::getDeclaration(
+ M, VPID,
+ {VectorType::get(cast<VectorType>(Params[0]->getType())
+ ->getElementType()
+ ->getPointerElementType(),
+ cast<VectorType>(Params[0]->getType())),
+ Params[0]->getType()});
+ break;
+ case Intrinsic::vp_store:
+ VPFunc = Intrinsic::getDeclaration(
+ M, VPID,
+ {Params[1]->getType()->getPointerElementType(), Params[1]->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;
+}
+
Instruction::BinaryOps BinaryOpIntrinsic::getBinaryOp() const {
switch (getIntrinsicID()) {
case Intrinsic::uadd_with_overflow:
@@ -347,3 +543,34 @@ unsigned BinaryOpIntrinsic::getNoWrapKind() const {
else
return OverflowingBinaryOperator::NoUnsignedWrap;
}
+
+const GCStatepointInst *GCProjectionInst::getStatepoint() const {
+ const Value *Token = getArgOperand(0);
+
+ // 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 {
+ if (auto Opt = getStatepoint()->getOperandBundle(LLVMContext::OB_gc_live))
+ return *(Opt->Inputs.begin() + getBasePtrIndex());
+ return *(getStatepoint()->arg_begin() + getBasePtrIndex());
+}
+
+Value *GCRelocateInst::getDerivedPtr() const {
+ if (auto Opt = getStatepoint()->getOperandBundle(LLVMContext::OB_gc_live))
+ return *(Opt->Inputs.begin() + getDerivedPtrIndex());
+ return *(getStatepoint()->arg_begin() + getDerivedPtrIndex());
+}