[IR] Add SaturatingInst and BinaryOpIntrinsic classes
Based on the suggestion in D62447, this adds a SaturatingInst class
that represents the saturating add/sub family of intrinsics. It
exposes the same interface as WithOverflowInst, for this reason I
have also added a common base class BinaryOpIntrinsic that holds the
actual implementation code and will be useful in some places handling
both overflowing and saturating math.
Differential Revision: https://reviews.llvm.org/D62466
llvm-svn: 361857
diff --git a/llvm/include/llvm/IR/IntrinsicInst.h b/llvm/include/llvm/IR/IntrinsicInst.h
index da9823b..9b816b0 100644
--- a/llvm/include/llvm/IR/IntrinsicInst.h
+++ b/llvm/include/llvm/IR/IntrinsicInst.h
@@ -267,8 +267,9 @@
}
};
- /// This class represents a op.with.overflow intrinsic.
- class WithOverflowInst : public IntrinsicInst {
+ /// This class represents an intrinsic that is based on a binary operation.
+ /// This includes op.with.overflow and saturating add/sub intrinsics.
+ class BinaryOpIntrinsic : public IntrinsicInst {
public:
static bool classof(const IntrinsicInst *I) {
switch (I->getIntrinsicID()) {
@@ -278,6 +279,10 @@
case Intrinsic::ssub_with_overflow:
case Intrinsic::umul_with_overflow:
case Intrinsic::smul_with_overflow:
+ case Intrinsic::uadd_sat:
+ case Intrinsic::sadd_sat:
+ case Intrinsic::usub_sat:
+ case Intrinsic::ssub_sat:
return true;
default:
return false;
@@ -300,6 +305,46 @@
unsigned getNoWrapKind() const;
};
+ /// Represents an op.with.overflow intrinsic.
+ class WithOverflowInst : public BinaryOpIntrinsic {
+ public:
+ static bool classof(const IntrinsicInst *I) {
+ switch (I->getIntrinsicID()) {
+ case Intrinsic::uadd_with_overflow:
+ case Intrinsic::sadd_with_overflow:
+ case Intrinsic::usub_with_overflow:
+ case Intrinsic::ssub_with_overflow:
+ case Intrinsic::umul_with_overflow:
+ case Intrinsic::smul_with_overflow:
+ return true;
+ default:
+ return false;
+ }
+ }
+ static bool classof(const Value *V) {
+ return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
+ }
+ };
+
+ /// Represents a saturating add/sub intrinsic.
+ class SaturatingInst : public BinaryOpIntrinsic {
+ public:
+ static bool classof(const IntrinsicInst *I) {
+ switch (I->getIntrinsicID()) {
+ case Intrinsic::uadd_sat:
+ case Intrinsic::sadd_sat:
+ case Intrinsic::usub_sat:
+ case Intrinsic::ssub_sat:
+ return true;
+ default:
+ return false;
+ }
+ }
+ static bool classof(const Value *V) {
+ return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
+ }
+ };
+
/// Common base class for all memory intrinsics. Simply provides
/// common methods.
/// Written as CRTP to avoid a common base class amongst the
diff --git a/llvm/lib/IR/IntrinsicInst.cpp b/llvm/lib/IR/IntrinsicInst.cpp
index 7ff8631..793e289 100644
--- a/llvm/lib/IR/IntrinsicInst.cpp
+++ b/llvm/lib/IR/IntrinsicInst.cpp
@@ -171,13 +171,17 @@
}
}
-Instruction::BinaryOps WithOverflowInst::getBinaryOp() const {
+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:
@@ -187,18 +191,20 @@
}
}
-bool WithOverflowInst::isSigned() const {
+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 WithOverflowInst::getNoWrapKind() const {
+unsigned BinaryOpIntrinsic::getNoWrapKind() const {
if (isSigned())
return OverflowingBinaryOperator::NoSignedWrap;
else