From 897bdca4b81dff200714a5b1cb22b20e9c4c4594 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 25 Jul 2020 16:21:55 +0200 Subject: [PATCH] [ConstantRange] Add API for intrinsics (NFC) This adds a common API for compute constant ranges of intrinsics. The intention here is that a) we can reuse the same code across different passes that handle constant ranges, i.e. this can be reused in SCCP b) we only have to add knowledge about supported intrinsics to ConstantRange, not any consumers. Differential Revision: https://reviews.llvm.org/D84587 --- llvm/include/llvm/IR/ConstantRange.h | 8 +++++ llvm/lib/Analysis/LazyValueInfo.cpp | 51 ++++++++-------------------- llvm/lib/IR/ConstantRange.cpp | 30 ++++++++++++++++ 3 files changed, 53 insertions(+), 36 deletions(-) diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h index 8ecb9aa0ce020..a027292ea43f4 100644 --- a/llvm/include/llvm/IR/ConstantRange.h +++ b/llvm/include/llvm/IR/ConstantRange.h @@ -150,6 +150,14 @@ class LLVM_NODISCARD ConstantRange { const APInt &Other, unsigned NoWrapKind); + /// Returns true if ConstantRange calculations are supported for intrinsic + /// with \p IntrinsicID. + static bool isIntrinsicSupported(Intrinsic::ID IntrinsicID); + + /// Compute range of intrinsic result for the given operand ranges. + static ConstantRange intrinsic(Intrinsic::ID IntrinsicID, + ArrayRef Ops); + /// Set up \p Pred and \p RHS such that /// ConstantRange::makeExactICmpRegion(Pred, RHS) == *this. Return true if /// successful. diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp index 34cc81c4bf2a3..d326a442051a8 100644 --- a/llvm/lib/Analysis/LazyValueInfo.cpp +++ b/llvm/lib/Analysis/LazyValueInfo.cpp @@ -400,8 +400,6 @@ class LazyValueInfoImpl { BasicBlock *BB); Optional solveBlockValueOverflowIntrinsic( WithOverflowInst *WO, BasicBlock *BB); - Optional solveBlockValueSaturatingIntrinsic( - SaturatingInst *SI, BasicBlock *BB); Optional solveBlockValueIntrinsic(IntrinsicInst *II, BasicBlock *BB); Optional solveBlockValueExtractValue( @@ -1035,43 +1033,24 @@ LazyValueInfoImpl::solveBlockValueOverflowIntrinsic(WithOverflowInst *WO, }); } -Optional -LazyValueInfoImpl::solveBlockValueSaturatingIntrinsic(SaturatingInst *SI, - BasicBlock *BB) { - switch (SI->getIntrinsicID()) { - case Intrinsic::uadd_sat: - return solveBlockValueBinaryOpImpl( - SI, BB, [](const ConstantRange &CR1, const ConstantRange &CR2) { - return CR1.uadd_sat(CR2); - }); - case Intrinsic::usub_sat: - return solveBlockValueBinaryOpImpl( - SI, BB, [](const ConstantRange &CR1, const ConstantRange &CR2) { - return CR1.usub_sat(CR2); - }); - case Intrinsic::sadd_sat: - return solveBlockValueBinaryOpImpl( - SI, BB, [](const ConstantRange &CR1, const ConstantRange &CR2) { - return CR1.sadd_sat(CR2); - }); - case Intrinsic::ssub_sat: - return solveBlockValueBinaryOpImpl( - SI, BB, [](const ConstantRange &CR1, const ConstantRange &CR2) { - return CR1.ssub_sat(CR2); - }); - default: - llvm_unreachable("All llvm.sat intrinsic are handled."); - } -} - Optional LazyValueInfoImpl::solveBlockValueIntrinsic( IntrinsicInst *II, BasicBlock *BB) { - if (auto *SI = dyn_cast(II)) - return solveBlockValueSaturatingIntrinsic(SI, BB); + if (!ConstantRange::isIntrinsicSupported(II->getIntrinsicID())) { + LLVM_DEBUG(dbgs() << " compute BB '" << BB->getName() + << "' - overdefined (unknown intrinsic).\n"); + return ValueLatticeElement::getOverdefined(); + } - LLVM_DEBUG(dbgs() << " compute BB '" << BB->getName() - << "' - overdefined (unknown intrinsic).\n"); - return ValueLatticeElement::getOverdefined(); + SmallVector OpRanges; + for (Value *Op : II->args()) { + Optional Range = getRangeFor(Op, II, BB); + if (!Range) + return None; + OpRanges.push_back(*Range); + } + + return ValueLatticeElement::getRange( + ConstantRange::intrinsic(II->getIntrinsicID(), OpRanges)); } Optional LazyValueInfoImpl::solveBlockValueExtractValue( diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index eabaaa203927f..26cff911cd675 100644 --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -26,6 +26,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Operator.h" #include "llvm/Support/Compiler.h" @@ -835,6 +836,35 @@ ConstantRange ConstantRange::overflowingBinaryOp(Instruction::BinaryOps BinOp, } } +bool ConstantRange::isIntrinsicSupported(Intrinsic::ID IntrinsicID) { + switch (IntrinsicID) { + case Intrinsic::uadd_sat: + case Intrinsic::usub_sat: + case Intrinsic::sadd_sat: + case Intrinsic::ssub_sat: + return true; + default: + return false; + } +} + +ConstantRange ConstantRange::intrinsic(Intrinsic::ID IntrinsicID, + ArrayRef Ops) { + switch (IntrinsicID) { + case Intrinsic::uadd_sat: + return Ops[0].uadd_sat(Ops[1]); + case Intrinsic::usub_sat: + return Ops[0].usub_sat(Ops[1]); + case Intrinsic::sadd_sat: + return Ops[0].sadd_sat(Ops[1]); + case Intrinsic::ssub_sat: + return Ops[0].ssub_sat(Ops[1]); + default: + assert(!isIntrinsicSupported(IntrinsicID) && "Shouldn't be supported"); + llvm_unreachable("Unsupported intrinsic"); + } +} + ConstantRange ConstantRange::add(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet())