[ConstantRange] Add umul_sat()/smul_sat() methods

Summary:
To be used in `ConstantRange::mulWithNoOverflow()`,
may in future be useful for when saturating shift/mul ops are added.

These are precise as far as i can tell.

I initially though i will need `APInt::[us]mul_sat()` for these,
but it turned out much simpler to do what `ConstantRange::multiply()`
does - perform multiplication in twice the bitwidth, and then truncate.
Though here we want saturating signed truncation.

Reviewers: nikic, reames, spatel

Reviewed By: nikic

Subscribers: hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D69994
diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp
index 7440574..d8befa8 100644
--- a/llvm/unittests/IR/ConstantRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeTest.cpp
@@ -2217,6 +2217,14 @@
       });
 }
 
+TEST_F(ConstantRangeTest, UMulSat) {
+  TestUnsignedBinOpExhaustive(
+      [](const ConstantRange &CR1, const ConstantRange &CR2) {
+        return CR1.umul_sat(CR2);
+      },
+      [](const APInt &N1, const APInt &N2) { return N1.umul_sat(N2); });
+}
+
 TEST_F(ConstantRangeTest, UShlSat) {
   TestUnsignedBinOpExhaustive(
       [](const ConstantRange &CR1, const ConstantRange &CR2) {
@@ -2245,6 +2253,14 @@
       });
 }
 
+TEST_F(ConstantRangeTest, SMulSat) {
+  TestSignedBinOpExhaustive(
+      [](const ConstantRange &CR1, const ConstantRange &CR2) {
+        return CR1.smul_sat(CR2);
+      },
+      [](const APInt &N1, const APInt &N2) { return N1.smul_sat(N2); });
+}
+
 TEST_F(ConstantRangeTest, SShlSat) {
   TestSignedBinOpExhaustive(
       [](const ConstantRange &CR1, const ConstantRange &CR2) {