From 3a98741a79e75696547a16fc82c2acefb840ec76 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 28 May 2019 18:08:06 +0000 Subject: [PATCH] [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 --- include/llvm/IR/IntrinsicInst.h | 49 +++++++++++++++++++++++++++++++-- lib/IR/IntrinsicInst.cpp | 12 ++++++-- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/include/llvm/IR/IntrinsicInst.h b/include/llvm/IR/IntrinsicInst.h index da9823b88c5..9b816b0a224 100644 --- a/include/llvm/IR/IntrinsicInst.h +++ b/include/llvm/IR/IntrinsicInst.h @@ -267,8 +267,9 @@ namespace llvm { } }; - /// 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 @@ namespace llvm { 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 @@ namespace llvm { 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(V) && classof(cast(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(V) && classof(cast(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/lib/IR/IntrinsicInst.cpp b/lib/IR/IntrinsicInst.cpp index 7ff8631c76f..793e2895dce 100644 --- a/lib/IR/IntrinsicInst.cpp +++ b/lib/IR/IntrinsicInst.cpp @@ -171,13 +171,17 @@ bool ConstrainedFPIntrinsic::isTernaryOp() const { } } -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 @@ Instruction::BinaryOps WithOverflowInst::getBinaryOp() const { } } -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