summaryrefslogtreecommitdiff
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.cpp239
1 files changed, 184 insertions, 55 deletions
diff --git a/llvm/lib/IR/IntrinsicInst.cpp b/llvm/lib/IR/IntrinsicInst.cpp
index b23742b83c129..c4e06cd979ed6 100644
--- a/llvm/lib/IR/IntrinsicInst.cpp
+++ b/llvm/lib/IR/IntrinsicInst.cpp
@@ -21,13 +21,15 @@
//===----------------------------------------------------------------------===//
#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/IR/Operator.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/Operator.h"
+#include "llvm/IR/PatternMatch.h"
+
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -102,7 +104,7 @@ Value *InstrProfIncrementInst::getStep() const {
return ConstantInt::get(Type::getInt64Ty(Context), 1);
}
-Optional<fp::RoundingMode> ConstrainedFPIntrinsic::getRoundingMode() const {
+Optional<RoundingMode> ConstrainedFPIntrinsic::getRoundingMode() const {
unsigned NumOperands = getNumArgOperands();
Metadata *MD =
cast<MetadataAsValue>(getArgOperand(NumOperands - 2))->getMetadata();
@@ -121,55 +123,53 @@ ConstrainedFPIntrinsic::getExceptionBehavior() const {
return StrToExceptionBehavior(cast<MDString>(MD)->getString());
}
-FCmpInst::Predicate
-ConstrainedFPCmpIntrinsic::getPredicate() const {
- Metadata *MD =
- cast<MetadataAsValue>(getArgOperand(2))->getMetadata();
+FCmpInst::Predicate ConstrainedFPCmpIntrinsic::getPredicate() const {
+ Metadata *MD = cast<MetadataAsValue>(getArgOperand(2))->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);
+ .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);
}
bool ConstrainedFPIntrinsic::isUnaryOp() const {
switch (getIntrinsicID()) {
- default:
- return false;
-#define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN) \
- case Intrinsic::INTRINSIC: \
- return NARG == 1;
+ 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, DAGN) \
- case Intrinsic::INTRINSIC: \
- return NARG == 3;
+ 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, DAGN) \
+#define INSTRUCTION(NAME, NARGS, ROUND_MODE, INTRINSIC) \
case Intrinsic::INTRINSIC:
#include "llvm/IR/ConstrainedOps.def"
return true;
@@ -178,36 +178,165 @@ bool ConstrainedFPIntrinsic::classof(const IntrinsicInst *I) {
}
}
+ElementCount VPIntrinsic::getStaticVectorLength() const {
+ auto GetVectorLengthOfType = [](const Type *T) -> ElementCount {
+ auto VT = cast<VectorType>(T);
+ auto ElemCount = VT->getElementCount();
+ return ElemCount;
+ };
+
+ auto VPMask = getMaskParam();
+ return GetVectorLengthOfType(VPMask->getType());
+}
+
+Value *VPIntrinsic::getMaskParam() const {
+ auto maskPos = GetMaskParamPos(getIntrinsicID());
+ if (maskPos)
+ return getArgOperand(maskPos.getValue());
+ return nullptr;
+}
+
+Value *VPIntrinsic::getVectorLengthParam() const {
+ auto vlenPos = GetVectorLengthParamPos(getIntrinsicID());
+ if (vlenPos)
+ return getArgOperand(vlenPos.getValue());
+ return nullptr;
+}
+
+Optional<int> VPIntrinsic::GetMaskParamPos(Intrinsic::ID IntrinsicID) {
+ switch (IntrinsicID) {
+ default:
+ return None;
+
+#define REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \
+ case Intrinsic::VPID: \
+ return MASKPOS;
+#include "llvm/IR/VPIntrinsics.def"
+ }
+}
+
+Optional<int> VPIntrinsic::GetVectorLengthParamPos(Intrinsic::ID IntrinsicID) {
+ switch (IntrinsicID) {
+ default:
+ return None;
+
+#define REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \
+ case Intrinsic::VPID: \
+ return VLENPOS;
+#include "llvm/IR/VPIntrinsics.def"
+ }
+}
+
+bool VPIntrinsic::IsVPIntrinsic(Intrinsic::ID ID) {
+ switch (ID) {
+ default:
+ return false;
+
+#define REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \
+ case Intrinsic::VPID: \
+ break;
+#include "llvm/IR/VPIntrinsics.def"
+ }
+ return true;
+}
+
+// Equivalent non-predicated opcode
+unsigned VPIntrinsic::GetFunctionalOpcodeForVP(Intrinsic::ID ID) {
+ switch (ID) {
+ default:
+ return Instruction::Call;
+
+#define HANDLE_VP_TO_OC(VPID, OC) \
+ case Intrinsic::VPID: \
+ return Instruction::OC;
+#include "llvm/IR/VPIntrinsics.def"
+ }
+}
+
+Intrinsic::ID VPIntrinsic::GetForOpcode(unsigned OC) {
+ switch (OC) {
+ default:
+ return Intrinsic::not_intrinsic;
+
+#define HANDLE_VP_TO_OC(VPID, OC) \
+ case Instruction::OC: \
+ return Intrinsic::VPID;
+#include "llvm/IR/VPIntrinsics.def"
+ }
+}
+
+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.Min"
+ if (EC.Scalable) {
+ // Undig the DL
+ 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.Min;
+ return (EC.Min == 1) && match(VLParam, m_VScale(DL));
+ }
+
+ // standard SIMD operation
+ auto VLConst = dyn_cast<ConstantInt>(VLParam);
+ if (!VLConst)
+ return false;
+
+ uint64_t VLNum = VLConst->getZExtValue();
+ if (VLNum >= EC.Min)
+ return true;
+
+ return false;
+}
+
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");
+ 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;
+ 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;
}
}