Skip to content

Commit 9ca363d

Browse files
committed
[APInt] Add saturating truncation methods
Summary: The signed one is needed for implementation of `ConstantRange::smul_sat()`, unsigned is for completeness only. Reviewers: nikic, RKSimon, spatel Reviewed By: nikic Subscribers: hiraditya, dexonsmith, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D69993
1 parent 1f592ec commit 9ca363d

File tree

3 files changed

+55
-0
lines changed

3 files changed

+55
-0
lines changed

llvm/include/llvm/ADT/APInt.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,19 @@ class LLVM_NODISCARD APInt {
13461346
/// that is greater than or equal to the current width.
13471347
APInt trunc(unsigned width) const;
13481348

1349+
/// Truncate to new width with unsigned saturation.
1350+
///
1351+
/// If the APInt, treated as unsigned integer, can be losslessly truncated to
1352+
/// the new bitwidth, then return truncated APInt. Else, return max value.
1353+
APInt truncUSat(unsigned width) const;
1354+
1355+
/// Truncate to new width with signed saturation.
1356+
///
1357+
/// If this APInt, treated as signed integer, can be losslessly truncated to
1358+
/// the new bitwidth, then return truncated APInt. Else, return either
1359+
/// signed min value if the APInt was negative, or signed max value.
1360+
APInt truncSSat(unsigned width) const;
1361+
13491362
/// Sign extend to a new width.
13501363
///
13511364
/// This operation sign extends the APInt to a new width. If the high order

llvm/lib/Support/APInt.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,31 @@ APInt APInt::trunc(unsigned width) const {
884884
return Result;
885885
}
886886

887+
// Truncate to new width with unsigned saturation.
888+
APInt APInt::truncUSat(unsigned width) const {
889+
assert(width < BitWidth && "Invalid APInt Truncate request");
890+
assert(width && "Can't truncate to 0 bits");
891+
892+
// Can we just losslessly truncate it?
893+
if (isIntN(width))
894+
return trunc(width);
895+
// If not, then just return the new limit.
896+
return APInt::getMaxValue(width);
897+
}
898+
899+
// Truncate to new width with signed saturation.
900+
APInt APInt::truncSSat(unsigned width) const {
901+
assert(width < BitWidth && "Invalid APInt Truncate request");
902+
assert(width && "Can't truncate to 0 bits");
903+
904+
// Can we just losslessly truncate it?
905+
if (isSignedIntN(width))
906+
return trunc(width);
907+
// If not, then just return the new limits.
908+
return isNegative() ? APInt::getSignedMinValue(width)
909+
: APInt::getSignedMaxValue(width);
910+
}
911+
887912
// Sign extend to a new width.
888913
APInt APInt::sext(unsigned Width) const {
889914
assert(Width > BitWidth && "Invalid APInt SignExtend request");

llvm/unittests/ADT/APIntTest.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,9 +1177,26 @@ TEST(APIntTest, fromString) {
11771177

11781178
TEST(APIntTest, SaturatingMath) {
11791179
APInt AP_10 = APInt(8, 10);
1180+
APInt AP_42 = APInt(8, 42);
11801181
APInt AP_100 = APInt(8, 100);
11811182
APInt AP_200 = APInt(8, 200);
11821183

1184+
EXPECT_EQ(APInt(7, 100), AP_100.truncUSat(7));
1185+
EXPECT_EQ(APInt(6, 63), AP_100.truncUSat(6));
1186+
EXPECT_EQ(APInt(5, 31), AP_100.truncUSat(5));
1187+
1188+
EXPECT_EQ(APInt(7, 127), AP_200.truncUSat(7));
1189+
EXPECT_EQ(APInt(6, 63), AP_200.truncUSat(6));
1190+
EXPECT_EQ(APInt(5, 31), AP_200.truncUSat(5));
1191+
1192+
EXPECT_EQ(APInt(7, 42), AP_42.truncSSat(7));
1193+
EXPECT_EQ(APInt(6, 31), AP_42.truncSSat(6));
1194+
EXPECT_EQ(APInt(5, 15), AP_42.truncSSat(5));
1195+
1196+
EXPECT_EQ(APInt(7, -56), AP_200.truncSSat(7));
1197+
EXPECT_EQ(APInt(6, -32), AP_200.truncSSat(6));
1198+
EXPECT_EQ(APInt(5, -16), AP_200.truncSSat(5));
1199+
11831200
EXPECT_EQ(APInt(8, 200), AP_100.uadd_sat(AP_100));
11841201
EXPECT_EQ(APInt(8, 255), AP_100.uadd_sat(AP_200));
11851202
EXPECT_EQ(APInt(8, 255), APInt(8, 255).uadd_sat(APInt(8, 255)));

0 commit comments

Comments
 (0)