CheckedArithmetic: llvm::Optional => std::optional

This commit is contained in:
Fangrui Song 2022-12-05 04:30:54 +00:00
parent 4b1b9e22b3
commit 3dfacc0a56
5 changed files with 25 additions and 25 deletions

View File

@ -560,7 +560,7 @@ uint64_t EmulateInstructionARM64::
AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bit carry_in, AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bit carry_in,
EmulateInstructionARM64::ProcState &proc_state) { EmulateInstructionARM64::ProcState &proc_state) {
uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in); uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in);
llvm::Optional<int64_t> signed_sum = llvm::checkedAdd(SInt(x), SInt(y)); std::optional<int64_t> signed_sum = llvm::checkedAdd(SInt(x), SInt(y));
bool overflow = !signed_sum; bool overflow = !signed_sum;
if (!overflow) if (!overflow)
overflow |= !llvm::checkedAdd(*signed_sum, SInt(carry_in)); overflow |= !llvm::checkedAdd(*signed_sum, SInt(carry_in));

View File

@ -641,7 +641,7 @@ public:
/// \returns false if the instruction doesn't belong to the group. /// \returns false if the instruction doesn't belong to the group.
bool insertMember(InstTy *Instr, int32_t Index, Align NewAlign) { bool insertMember(InstTy *Instr, int32_t Index, Align NewAlign) {
// Make sure the key fits in an int32_t. // Make sure the key fits in an int32_t.
Optional<int32_t> MaybeKey = checkedAdd(Index, SmallestKey); std::optional<int32_t> MaybeKey = checkedAdd(Index, SmallestKey);
if (!MaybeKey) if (!MaybeKey)
return false; return false;
int32_t Key = *MaybeKey; int32_t Key = *MaybeKey;
@ -664,7 +664,7 @@ public:
} else if (Key < SmallestKey) { } else if (Key < SmallestKey) {
// Make sure the largest index fits in an int32_t. // Make sure the largest index fits in an int32_t.
Optional<int32_t> MaybeLargestIndex = checkedSub(LargestKey, Key); std::optional<int32_t> MaybeLargestIndex = checkedSub(LargestKey, Key);
if (!MaybeLargestIndex) if (!MaybeLargestIndex)
return false; return false;

View File

@ -15,8 +15,8 @@
#define LLVM_SUPPORT_CHECKEDARITHMETIC_H #define LLVM_SUPPORT_CHECKEDARITHMETIC_H
#include "llvm/ADT/APInt.h" #include "llvm/ADT/APInt.h"
#include "llvm/ADT/Optional.h"
#include <optional>
#include <type_traits> #include <type_traits>
namespace { namespace {
@ -26,7 +26,7 @@ namespace {
/// \return Empty optional if the operation overflows, or result otherwise. /// \return Empty optional if the operation overflows, or result otherwise.
template <typename T, typename F> template <typename T, typename F>
std::enable_if_t<std::is_integral<T>::value && sizeof(T) * 8 <= 64, std::enable_if_t<std::is_integral<T>::value && sizeof(T) * 8 <= 64,
llvm::Optional<T>> std::optional<T>>
checkedOp(T LHS, T RHS, F Op, bool Signed = true) { checkedOp(T LHS, T RHS, F Op, bool Signed = true) {
llvm::APInt ALHS(sizeof(T) * 8, LHS, Signed); llvm::APInt ALHS(sizeof(T) * 8, LHS, Signed);
llvm::APInt ARHS(sizeof(T) * 8, RHS, Signed); llvm::APInt ARHS(sizeof(T) * 8, RHS, Signed);
@ -44,7 +44,7 @@ namespace llvm {
/// \return Optional of sum if no signed overflow occurred, /// \return Optional of sum if no signed overflow occurred,
/// \c None otherwise. /// \c None otherwise.
template <typename T> template <typename T>
std::enable_if_t<std::is_signed<T>::value, llvm::Optional<T>> std::enable_if_t<std::is_signed<T>::value, std::optional<T>>
checkedAdd(T LHS, T RHS) { checkedAdd(T LHS, T RHS) {
return checkedOp(LHS, RHS, &llvm::APInt::sadd_ov); return checkedOp(LHS, RHS, &llvm::APInt::sadd_ov);
} }
@ -53,7 +53,7 @@ checkedAdd(T LHS, T RHS) {
/// \return Optional of sum if no signed overflow occurred, /// \return Optional of sum if no signed overflow occurred,
/// \c None otherwise. /// \c None otherwise.
template <typename T> template <typename T>
std::enable_if_t<std::is_signed<T>::value, llvm::Optional<T>> std::enable_if_t<std::is_signed<T>::value, std::optional<T>>
checkedSub(T LHS, T RHS) { checkedSub(T LHS, T RHS) {
return checkedOp(LHS, RHS, &llvm::APInt::ssub_ov); return checkedOp(LHS, RHS, &llvm::APInt::ssub_ov);
} }
@ -62,7 +62,7 @@ checkedSub(T LHS, T RHS) {
/// \return Optional of product if no signed overflow occurred, /// \return Optional of product if no signed overflow occurred,
/// \c None otherwise. /// \c None otherwise.
template <typename T> template <typename T>
std::enable_if_t<std::is_signed<T>::value, llvm::Optional<T>> std::enable_if_t<std::is_signed<T>::value, std::optional<T>>
checkedMul(T LHS, T RHS) { checkedMul(T LHS, T RHS) {
return checkedOp(LHS, RHS, &llvm::APInt::smul_ov); return checkedOp(LHS, RHS, &llvm::APInt::smul_ov);
} }
@ -71,7 +71,7 @@ checkedMul(T LHS, T RHS) {
/// \return Optional of result if no signed overflow occurred, /// \return Optional of result if no signed overflow occurred,
/// \c None otherwise. /// \c None otherwise.
template <typename T> template <typename T>
std::enable_if_t<std::is_signed<T>::value, llvm::Optional<T>> std::enable_if_t<std::is_signed<T>::value, std::optional<T>>
checkedMulAdd(T A, T B, T C) { checkedMulAdd(T A, T B, T C) {
if (auto Product = checkedMul(A, B)) if (auto Product = checkedMul(A, B))
return checkedAdd(*Product, C); return checkedAdd(*Product, C);
@ -82,7 +82,7 @@ checkedMulAdd(T A, T B, T C) {
/// \return Optional of sum if no unsigned overflow occurred, /// \return Optional of sum if no unsigned overflow occurred,
/// \c None otherwise. /// \c None otherwise.
template <typename T> template <typename T>
std::enable_if_t<std::is_unsigned<T>::value, llvm::Optional<T>> std::enable_if_t<std::is_unsigned<T>::value, std::optional<T>>
checkedAddUnsigned(T LHS, T RHS) { checkedAddUnsigned(T LHS, T RHS) {
return checkedOp(LHS, RHS, &llvm::APInt::uadd_ov, /*Signed=*/false); return checkedOp(LHS, RHS, &llvm::APInt::uadd_ov, /*Signed=*/false);
} }
@ -91,7 +91,7 @@ checkedAddUnsigned(T LHS, T RHS) {
/// \return Optional of product if no unsigned overflow occurred, /// \return Optional of product if no unsigned overflow occurred,
/// \c None otherwise. /// \c None otherwise.
template <typename T> template <typename T>
std::enable_if_t<std::is_unsigned<T>::value, llvm::Optional<T>> std::enable_if_t<std::is_unsigned<T>::value, std::optional<T>>
checkedMulUnsigned(T LHS, T RHS) { checkedMulUnsigned(T LHS, T RHS) {
return checkedOp(LHS, RHS, &llvm::APInt::umul_ov, /*Signed=*/false); return checkedOp(LHS, RHS, &llvm::APInt::umul_ov, /*Signed=*/false);
} }
@ -100,7 +100,7 @@ checkedMulUnsigned(T LHS, T RHS) {
/// \return Optional of result if no unsigned overflow occurred, /// \return Optional of result if no unsigned overflow occurred,
/// \c None otherwise. /// \c None otherwise.
template <typename T> template <typename T>
std::enable_if_t<std::is_unsigned<T>::value, llvm::Optional<T>> std::enable_if_t<std::is_unsigned<T>::value, std::optional<T>>
checkedMulAddUnsigned(T A, T B, T C) { checkedMulAddUnsigned(T A, T B, T C) {
if (auto Product = checkedMulUnsigned(A, B)) if (auto Product = checkedMulUnsigned(A, B))
return checkedAddUnsigned(*Product, C); return checkedAddUnsigned(*Product, C);

View File

@ -206,7 +206,7 @@ Expected<ExpressionValue> llvm::operator+(const ExpressionValue &LeftOperand,
if (LeftOperand.isNegative() && RightOperand.isNegative()) { if (LeftOperand.isNegative() && RightOperand.isNegative()) {
int64_t LeftValue = cantFail(LeftOperand.getSignedValue()); int64_t LeftValue = cantFail(LeftOperand.getSignedValue());
int64_t RightValue = cantFail(RightOperand.getSignedValue()); int64_t RightValue = cantFail(RightOperand.getSignedValue());
Optional<int64_t> Result = checkedAdd<int64_t>(LeftValue, RightValue); std::optional<int64_t> Result = checkedAdd<int64_t>(LeftValue, RightValue);
if (!Result) if (!Result)
return make_error<OverflowError>(); return make_error<OverflowError>();
@ -224,7 +224,7 @@ Expected<ExpressionValue> llvm::operator+(const ExpressionValue &LeftOperand,
// Both values are positive at this point. // Both values are positive at this point.
uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue());
uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
Optional<uint64_t> Result = std::optional<uint64_t> Result =
checkedAddUnsigned<uint64_t>(LeftValue, RightValue); checkedAddUnsigned<uint64_t>(LeftValue, RightValue);
if (!Result) if (!Result)
return make_error<OverflowError>(); return make_error<OverflowError>();
@ -241,7 +241,7 @@ Expected<ExpressionValue> llvm::operator-(const ExpressionValue &LeftOperand,
// Result <= -1 - (max int64_t) which overflows on 1- and 2-complement. // Result <= -1 - (max int64_t) which overflows on 1- and 2-complement.
if (RightValue > (uint64_t)std::numeric_limits<int64_t>::max()) if (RightValue > (uint64_t)std::numeric_limits<int64_t>::max())
return make_error<OverflowError>(); return make_error<OverflowError>();
Optional<int64_t> Result = std::optional<int64_t> Result =
checkedSub(LeftValue, static_cast<int64_t>(RightValue)); checkedSub(LeftValue, static_cast<int64_t>(RightValue));
if (!Result) if (!Result)
return make_error<OverflowError>(); return make_error<OverflowError>();
@ -306,7 +306,7 @@ Expected<ExpressionValue> llvm::operator*(const ExpressionValue &LeftOperand,
// Result will be positive and can overflow. // Result will be positive and can overflow.
uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue());
uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
Optional<uint64_t> Result = std::optional<uint64_t> Result =
checkedMulUnsigned<uint64_t>(LeftValue, RightValue); checkedMulUnsigned<uint64_t>(LeftValue, RightValue);
if (!Result) if (!Result)
return make_error<OverflowError>(); return make_error<OverflowError>();

View File

@ -11,7 +11,7 @@ TEST(CheckedArithmetic, CheckedAdd) {
EXPECT_EQ(checkedAdd<int64_t>(Max, Max), std::nullopt); EXPECT_EQ(checkedAdd<int64_t>(Max, Max), std::nullopt);
EXPECT_EQ(checkedAdd<int64_t>(Min, -1), std::nullopt); EXPECT_EQ(checkedAdd<int64_t>(Min, -1), std::nullopt);
EXPECT_EQ(checkedAdd<int64_t>(Max, 1), std::nullopt); EXPECT_EQ(checkedAdd<int64_t>(Max, 1), std::nullopt);
EXPECT_EQ(checkedAdd<int64_t>(10, 1), Optional<int64_t>(11)); EXPECT_EQ(checkedAdd<int64_t>(10, 1), std::optional<int64_t>(11));
} }
TEST(CheckedArithmetic, CheckedAddSmall) { TEST(CheckedArithmetic, CheckedAddSmall) {
@ -20,7 +20,7 @@ TEST(CheckedArithmetic, CheckedAddSmall) {
EXPECT_EQ(checkedAdd<int16_t>(Max, Max), std::nullopt); EXPECT_EQ(checkedAdd<int16_t>(Max, Max), std::nullopt);
EXPECT_EQ(checkedAdd<int16_t>(Min, -1), std::nullopt); EXPECT_EQ(checkedAdd<int16_t>(Min, -1), std::nullopt);
EXPECT_EQ(checkedAdd<int16_t>(Max, 1), std::nullopt); EXPECT_EQ(checkedAdd<int16_t>(Max, 1), std::nullopt);
EXPECT_EQ(checkedAdd<int16_t>(10, 1), Optional<int64_t>(11)); EXPECT_EQ(checkedAdd<int16_t>(10, 1), std::optional<int64_t>(11));
} }
TEST(CheckedArithmetic, CheckedMul) { TEST(CheckedArithmetic, CheckedMul) {
@ -29,7 +29,7 @@ TEST(CheckedArithmetic, CheckedMul) {
EXPECT_EQ(checkedMul<int64_t>(Max, 2), std::nullopt); EXPECT_EQ(checkedMul<int64_t>(Max, 2), std::nullopt);
EXPECT_EQ(checkedMul<int64_t>(Max, Max), std::nullopt); EXPECT_EQ(checkedMul<int64_t>(Max, Max), std::nullopt);
EXPECT_EQ(checkedMul<int64_t>(Min, 2), std::nullopt); EXPECT_EQ(checkedMul<int64_t>(Min, 2), std::nullopt);
EXPECT_EQ(checkedMul<int64_t>(10, 2), Optional<int64_t>(20)); EXPECT_EQ(checkedMul<int64_t>(10, 2), std::optional<int64_t>(20));
} }
TEST(CheckedArithmetic, CheckedMulAdd) { TEST(CheckedArithmetic, CheckedMulAdd) {
@ -38,7 +38,7 @@ TEST(CheckedArithmetic, CheckedMulAdd) {
EXPECT_EQ(checkedMulAdd<int64_t>(Max, 1, 2), std::nullopt); EXPECT_EQ(checkedMulAdd<int64_t>(Max, 1, 2), std::nullopt);
EXPECT_EQ(checkedMulAdd<int64_t>(1, 1, Max), std::nullopt); EXPECT_EQ(checkedMulAdd<int64_t>(1, 1, Max), std::nullopt);
EXPECT_EQ(checkedMulAdd<int64_t>(1, -1, Min), std::nullopt); EXPECT_EQ(checkedMulAdd<int64_t>(1, -1, Min), std::nullopt);
EXPECT_EQ(checkedMulAdd<int64_t>(10, 2, 3), Optional<int64_t>(23)); EXPECT_EQ(checkedMulAdd<int64_t>(10, 2, 3), std::optional<int64_t>(23));
} }
TEST(CheckedArithmetic, CheckedMulSmall) { TEST(CheckedArithmetic, CheckedMulSmall) {
@ -47,7 +47,7 @@ TEST(CheckedArithmetic, CheckedMulSmall) {
EXPECT_EQ(checkedMul<int16_t>(Max, 2), std::nullopt); EXPECT_EQ(checkedMul<int16_t>(Max, 2), std::nullopt);
EXPECT_EQ(checkedMul<int16_t>(Max, Max), std::nullopt); EXPECT_EQ(checkedMul<int16_t>(Max, Max), std::nullopt);
EXPECT_EQ(checkedMul<int16_t>(Min, 2), std::nullopt); EXPECT_EQ(checkedMul<int16_t>(Min, 2), std::nullopt);
EXPECT_EQ(checkedMul<int16_t>(10, 2), Optional<int16_t>(20)); EXPECT_EQ(checkedMul<int16_t>(10, 2), std::optional<int16_t>(20));
} }
TEST(CheckedArithmetic, CheckedMulAddSmall) { TEST(CheckedArithmetic, CheckedMulAddSmall) {
@ -56,28 +56,28 @@ TEST(CheckedArithmetic, CheckedMulAddSmall) {
EXPECT_EQ(checkedMulAdd<int16_t>(Max, 1, 2), std::nullopt); EXPECT_EQ(checkedMulAdd<int16_t>(Max, 1, 2), std::nullopt);
EXPECT_EQ(checkedMulAdd<int16_t>(1, 1, Max), std::nullopt); EXPECT_EQ(checkedMulAdd<int16_t>(1, 1, Max), std::nullopt);
EXPECT_EQ(checkedMulAdd<int16_t>(1, -1, Min), std::nullopt); EXPECT_EQ(checkedMulAdd<int16_t>(1, -1, Min), std::nullopt);
EXPECT_EQ(checkedMulAdd<int16_t>(10, 2, 3), Optional<int16_t>(23)); EXPECT_EQ(checkedMulAdd<int16_t>(10, 2, 3), std::optional<int16_t>(23));
} }
TEST(CheckedArithmetic, CheckedAddUnsigned) { TEST(CheckedArithmetic, CheckedAddUnsigned) {
const uint64_t Max = std::numeric_limits<uint64_t>::max(); const uint64_t Max = std::numeric_limits<uint64_t>::max();
EXPECT_EQ(checkedAddUnsigned<uint64_t>(Max, Max), std::nullopt); EXPECT_EQ(checkedAddUnsigned<uint64_t>(Max, Max), std::nullopt);
EXPECT_EQ(checkedAddUnsigned<uint64_t>(Max, 1), std::nullopt); EXPECT_EQ(checkedAddUnsigned<uint64_t>(Max, 1), std::nullopt);
EXPECT_EQ(checkedAddUnsigned<uint64_t>(10, 1), Optional<uint64_t>(11)); EXPECT_EQ(checkedAddUnsigned<uint64_t>(10, 1), std::optional<uint64_t>(11));
} }
TEST(CheckedArithmetic, CheckedMulUnsigned) { TEST(CheckedArithmetic, CheckedMulUnsigned) {
const uint64_t Max = std::numeric_limits<uint64_t>::max(); const uint64_t Max = std::numeric_limits<uint64_t>::max();
EXPECT_EQ(checkedMulUnsigned<uint64_t>(Max, 2), std::nullopt); EXPECT_EQ(checkedMulUnsigned<uint64_t>(Max, 2), std::nullopt);
EXPECT_EQ(checkedMulUnsigned<uint64_t>(Max, Max), std::nullopt); EXPECT_EQ(checkedMulUnsigned<uint64_t>(Max, Max), std::nullopt);
EXPECT_EQ(checkedMulUnsigned<uint64_t>(10, 2), Optional<uint64_t>(20)); EXPECT_EQ(checkedMulUnsigned<uint64_t>(10, 2), std::optional<uint64_t>(20));
} }
TEST(CheckedArithmetic, CheckedMulAddUnsigned) { TEST(CheckedArithmetic, CheckedMulAddUnsigned) {
const uint64_t Max = std::numeric_limits<uint64_t>::max(); const uint64_t Max = std::numeric_limits<uint64_t>::max();
EXPECT_EQ(checkedMulAddUnsigned<uint64_t>(Max, 1, 2), std::nullopt); EXPECT_EQ(checkedMulAddUnsigned<uint64_t>(Max, 1, 2), std::nullopt);
EXPECT_EQ(checkedMulAddUnsigned<uint64_t>(1, 1, Max), std::nullopt); EXPECT_EQ(checkedMulAddUnsigned<uint64_t>(1, 1, Max), std::nullopt);
EXPECT_EQ(checkedMulAddUnsigned<uint64_t>(10, 2, 3), Optional<uint64_t>(23)); EXPECT_EQ(checkedMulAddUnsigned<uint64_t>(10, 2, 3), std::optional<uint64_t>(23));
} }