1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

[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
This commit is contained in:
Nikita Popov 2019-05-28 18:08:06 +00:00
parent 1cdac3fa17
commit 3a98741a79
2 changed files with 56 additions and 5 deletions

View File

@ -267,8 +267,9 @@ namespace llvm {
} }
}; };
/// This class represents a op.with.overflow intrinsic. /// This class represents an intrinsic that is based on a binary operation.
class WithOverflowInst : public IntrinsicInst { /// This includes op.with.overflow and saturating add/sub intrinsics.
class BinaryOpIntrinsic : public IntrinsicInst {
public: public:
static bool classof(const IntrinsicInst *I) { static bool classof(const IntrinsicInst *I) {
switch (I->getIntrinsicID()) { switch (I->getIntrinsicID()) {
@ -278,6 +279,10 @@ namespace llvm {
case Intrinsic::ssub_with_overflow: case Intrinsic::ssub_with_overflow:
case Intrinsic::umul_with_overflow: case Intrinsic::umul_with_overflow:
case Intrinsic::smul_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; return true;
default: default:
return false; return false;
@ -300,6 +305,46 @@ namespace llvm {
unsigned getNoWrapKind() const; 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 base class for all memory intrinsics. Simply provides
/// common methods. /// common methods.
/// Written as CRTP to avoid a common base class amongst the /// Written as CRTP to avoid a common base class amongst the

View File

@ -171,13 +171,17 @@ bool ConstrainedFPIntrinsic::isTernaryOp() const {
} }
} }
Instruction::BinaryOps WithOverflowInst::getBinaryOp() const { Instruction::BinaryOps BinaryOpIntrinsic::getBinaryOp() const {
switch (getIntrinsicID()) { switch (getIntrinsicID()) {
case Intrinsic::uadd_with_overflow: case Intrinsic::uadd_with_overflow:
case Intrinsic::sadd_with_overflow: case Intrinsic::sadd_with_overflow:
case Intrinsic::uadd_sat:
case Intrinsic::sadd_sat:
return Instruction::Add; return Instruction::Add;
case Intrinsic::usub_with_overflow: case Intrinsic::usub_with_overflow:
case Intrinsic::ssub_with_overflow: case Intrinsic::ssub_with_overflow:
case Intrinsic::usub_sat:
case Intrinsic::ssub_sat:
return Instruction::Sub; return Instruction::Sub;
case Intrinsic::umul_with_overflow: case Intrinsic::umul_with_overflow:
case Intrinsic::smul_with_overflow: case Intrinsic::smul_with_overflow:
@ -187,18 +191,20 @@ Instruction::BinaryOps WithOverflowInst::getBinaryOp() const {
} }
} }
bool WithOverflowInst::isSigned() const { bool BinaryOpIntrinsic::isSigned() const {
switch (getIntrinsicID()) { switch (getIntrinsicID()) {
case Intrinsic::sadd_with_overflow: case Intrinsic::sadd_with_overflow:
case Intrinsic::ssub_with_overflow: case Intrinsic::ssub_with_overflow:
case Intrinsic::smul_with_overflow: case Intrinsic::smul_with_overflow:
case Intrinsic::sadd_sat:
case Intrinsic::ssub_sat:
return true; return true;
default: default:
return false; return false;
} }
} }
unsigned WithOverflowInst::getNoWrapKind() const { unsigned BinaryOpIntrinsic::getNoWrapKind() const {
if (isSigned()) if (isSigned())
return OverflowingBinaryOperator::NoSignedWrap; return OverflowingBinaryOperator::NoSignedWrap;
else else