diff options
Diffstat (limited to 'llvm/lib/IR/IntrinsicInst.cpp')
-rw-r--r-- | llvm/lib/IR/IntrinsicInst.cpp | 287 |
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()); +} |