Skip to content

[ADT][APInt] add sfloordiv_ov APInt's member function #84720

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions llvm/include/llvm/ADT/APInt.h
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,12 @@ class [[nodiscard]] APInt {
APInt ushl_ov(const APInt &Amt, bool &Overflow) const;
APInt ushl_ov(unsigned Amt, bool &Overflow) const;

/// Signed integer floor division operation.
///
/// Rounds towards negative infinity, i.e. 5 / -2 = -3. Iff minimum value
/// divided by -1 set Overflow to true.
APInt sfloordiv_ov(const APInt &RHS, bool &Overflow) const;

// Operations that saturate
APInt sadd_sat(const APInt &RHS) const;
APInt uadd_sat(const APInt &RHS) const;
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Support/APInt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2022,6 +2022,13 @@ APInt APInt::ushl_ov(unsigned ShAmt, bool &Overflow) const {
return *this << ShAmt;
}

APInt APInt::sfloordiv_ov(const APInt &RHS, bool &Overflow) const {
APInt quotient = sdiv_ov(RHS, Overflow);
if ((quotient * RHS != *this) && (isNegative() != RHS.isNegative()))
return quotient - 1;
return quotient;
}

APInt APInt::sadd_sat(const APInt &RHS) const {
bool Overflow;
APInt Res = sadd_ov(RHS, Overflow);
Expand Down
64 changes: 64 additions & 0 deletions llvm/unittests/ADT/APIntTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "gtest/gtest.h"
#include <array>
#include <climits>
#include <limits>
#include <optional>

using namespace llvm;
Expand Down Expand Up @@ -3048,6 +3049,69 @@ TEST(APIntTest, smul_ov) {
}
}

TEST(APIntTest, sfloordiv_ov) {
// int16 test overflow
{
using IntTy = int16_t;
APInt divisor(8 * sizeof(IntTy), std::numeric_limits<IntTy>::lowest(),
true);
APInt dividend(8 * sizeof(IntTy), IntTy(-1), true);
bool Overflow = false;
(void)divisor.sfloordiv_ov(dividend, Overflow);
EXPECT_TRUE(Overflow);
}
// int32 test overflow
{
using IntTy = int32_t;
APInt divisor(8 * sizeof(IntTy), std::numeric_limits<IntTy>::lowest(),
true);
APInt dividend(8 * sizeof(IntTy), IntTy(-1), true);
bool Overflow = false;
(void)divisor.sfloordiv_ov(dividend, Overflow);
EXPECT_TRUE(Overflow);
}
// int64 test overflow
{
using IntTy = int64_t;
APInt divisor(8 * sizeof(IntTy), std::numeric_limits<IntTy>::lowest(),
true);
APInt dividend(8 * sizeof(IntTy), IntTy(-1), true);
bool Overflow = false;
(void)divisor.sfloordiv_ov(dividend, Overflow);
EXPECT_TRUE(Overflow);
}
// test all of int8
{
bool Overflow = false;
for (int i = -128; i < 128; ++i) {
for (int j = -128; j < 128; ++j) {
if (j == 0)
continue;

int8_t a = static_cast<int8_t>(i);
int8_t b = static_cast<int8_t>(j);

APInt divisor(8, a, true);
APInt dividend(8, b, true);
APInt quotient = divisor.sfloordiv_ov(dividend, Overflow);

if (i == -128 && j == -1) {
EXPECT_TRUE(Overflow);
continue;
}

if (((i >= 0 && j > 0) || (i <= 0 && j < 0)) ||
(i % j == 0)) // if quotient >= 0 and remain == 0 floordiv
// equivalent to div
EXPECT_EQ(quotient.getSExtValue(), a / b);
else
EXPECT_EQ(quotient.getSExtValue(), a / b - 1);
EXPECT_FALSE(Overflow);
}
}
}
}

TEST(APIntTest, SolveQuadraticEquationWrap) {
// Verify that "Solution" is the first non-negative integer that solves
// Ax^2 + Bx + C = "0 or overflow", i.e. that it is a correct solution
Expand Down