Skip to content

Commit 1980165

Browse files
committed
[ADT] Add implementations for avgFloor and avgCeil to APInt
Supports both signed and unsigned expansions. SelectionDAG now calls the APInt implementation of these functions.
1 parent d9c8550 commit 1980165

File tree

4 files changed

+102
-24
lines changed

4 files changed

+102
-24
lines changed

llvm/include/llvm/ADT/APInt.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2193,6 +2193,18 @@ inline const APInt absdiff(const APInt &A, const APInt &B) {
21932193
return A.uge(B) ? (A - B) : (B - A);
21942194
}
21952195

2196+
/// Compute the floor of the signed average of C1 and C2
2197+
APInt avgFloorS(const APInt &C1, const APInt &C2);
2198+
2199+
/// Compute the floor of the unsigned average of C1 and C2
2200+
APInt avgFloorU(const APInt &C1, const APInt &C2);
2201+
2202+
/// Compute the ceil of the signed average of C1 and C2
2203+
APInt avgCeilS(const APInt &C1, const APInt &C2);
2204+
2205+
/// Compute the ceil of the unsigned average of C1 and C2
2206+
APInt avgCeilU(const APInt &C1, const APInt &C2);
2207+
21962208
/// Compute GCD of two unsigned APInt values.
21972209
///
21982210
/// This function returns the greatest common divisor of the two APInt values

llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6021,30 +6021,14 @@ static std::optional<APInt> FoldValue(unsigned Opcode, const APInt &C1,
60216021
APInt C2Ext = C2.zext(FullWidth);
60226022
return (C1Ext * C2Ext).extractBits(C1.getBitWidth(), C1.getBitWidth());
60236023
}
6024-
case ISD::AVGFLOORS: {
6025-
unsigned FullWidth = C1.getBitWidth() + 1;
6026-
APInt C1Ext = C1.sext(FullWidth);
6027-
APInt C2Ext = C2.sext(FullWidth);
6028-
return (C1Ext + C2Ext).extractBits(C1.getBitWidth(), 1);
6029-
}
6030-
case ISD::AVGFLOORU: {
6031-
unsigned FullWidth = C1.getBitWidth() + 1;
6032-
APInt C1Ext = C1.zext(FullWidth);
6033-
APInt C2Ext = C2.zext(FullWidth);
6034-
return (C1Ext + C2Ext).extractBits(C1.getBitWidth(), 1);
6035-
}
6036-
case ISD::AVGCEILS: {
6037-
unsigned FullWidth = C1.getBitWidth() + 1;
6038-
APInt C1Ext = C1.sext(FullWidth);
6039-
APInt C2Ext = C2.sext(FullWidth);
6040-
return (C1Ext + C2Ext + 1).extractBits(C1.getBitWidth(), 1);
6041-
}
6042-
case ISD::AVGCEILU: {
6043-
unsigned FullWidth = C1.getBitWidth() + 1;
6044-
APInt C1Ext = C1.zext(FullWidth);
6045-
APInt C2Ext = C2.zext(FullWidth);
6046-
return (C1Ext + C2Ext + 1).extractBits(C1.getBitWidth(), 1);
6047-
}
6024+
case ISD::AVGFLOORS:
6025+
return APIntOps::avgFloorS(C1, C2);
6026+
case ISD::AVGFLOORU:
6027+
return APIntOps::avgFloorU(C1, C2);
6028+
case ISD::AVGCEILS:
6029+
return APIntOps::avgCeilS(C1, C2);
6030+
case ISD::AVGCEILU:
6031+
return APIntOps::avgCeilU(C1, C2);
60486032
case ISD::ABDS:
60496033
return APIntOps::smax(C1, C2) - APIntOps::smin(C1, C2);
60506034
case ISD::ABDU:

llvm/lib/Support/APInt.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3094,3 +3094,35 @@ void llvm::LoadIntFromMemory(APInt &IntVal, const uint8_t *Src,
30943094
memcpy(Dst + sizeof(uint64_t) - LoadBytes, Src, LoadBytes);
30953095
}
30963096
}
3097+
3098+
APInt APIntOps::avgFloorS(const APInt &C1, const APInt &C2) {
3099+
// Return floor((C1 + C2) /2))
3100+
unsigned FullWidth = C1.getBitWidth() + 1;
3101+
APInt C1Ext = C1.sext(FullWidth);
3102+
APInt C2Ext = C2.sext(FullWidth);
3103+
return (C1Ext + C2Ext).extractBits(C1.getBitWidth(), 1);
3104+
}
3105+
3106+
APInt APIntOps::avgFloorU(const APInt &C1, const APInt &C2) {
3107+
// Return floor((C1 + C2) /2))
3108+
unsigned FullWidth = C1.getBitWidth() + 1;
3109+
APInt C1Ext = C1.zext(FullWidth);
3110+
APInt C2Ext = C2.zext(FullWidth);
3111+
return (C1Ext + C2Ext).extractBits(C1.getBitWidth(), 1);
3112+
}
3113+
3114+
APInt APIntOps::avgCeilS(const APInt &C1, const APInt &C2) {
3115+
// Return ceil((C1 + C2) /2))
3116+
unsigned FullWidth = C1.getBitWidth() + 1;
3117+
APInt C1Ext = C1.sext(FullWidth);
3118+
APInt C2Ext = C2.sext(FullWidth);
3119+
return (C1Ext + C2Ext + 1).extractBits(C1.getBitWidth(), 1);
3120+
}
3121+
3122+
APInt APIntOps::avgCeilU(const APInt &C1, const APInt &C2) {
3123+
// Return ceil((C1 + C2) /2))
3124+
unsigned FullWidth = C1.getBitWidth() + 1;
3125+
APInt C1Ext = C1.zext(FullWidth);
3126+
APInt C2Ext = C2.zext(FullWidth);
3127+
return (C1Ext + C2Ext + 1).extractBits(C1.getBitWidth(), 1);
3128+
}

llvm/unittests/ADT/APIntTest.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2877,6 +2877,56 @@ TEST(APIntTest, RoundingSDiv) {
28772877
}
28782878
}
28792879

2880+
TEST(APIntTest, Average) {
2881+
APInt A2(32, 2);
2882+
APInt A100(32, 100);
2883+
APInt A101(32, 101);
2884+
APInt A200(32, 200, false);
2885+
APInt avg = APIntOps::avgFloorU(A100, A200);
2886+
2887+
EXPECT_EQ(APInt(32, 150), APIntOps::avgFloorU(A100, A200));
2888+
EXPECT_EQ(APIntOps::RoundingUDiv(A100 + A200, A2, APInt::Rounding::DOWN),
2889+
APIntOps::avgFloorU(A100, A200));
2890+
EXPECT_EQ(APIntOps::RoundingUDiv(A100 + A200, A2, APInt::Rounding::UP),
2891+
APIntOps::avgCeilU(A100, A200));
2892+
EXPECT_EQ(APIntOps::RoundingUDiv(A100 + A101, A2, APInt::Rounding::DOWN),
2893+
APIntOps::avgFloorU(A100, A101));
2894+
EXPECT_EQ(APIntOps::RoundingUDiv(A100 + A101, A2, APInt::Rounding::UP),
2895+
APIntOps::avgCeilU(A100, A101));
2896+
2897+
APInt Ap100(32, +100);
2898+
APInt Ap101(32, +101);
2899+
APInt Ap200(32, +200);
2900+
APInt Am100(32, -100);
2901+
APInt Am101(32, -101);
2902+
APInt Am200(32, -200);
2903+
EXPECT_EQ(APInt(32, +150), APIntOps::avgFloorS(Ap100, Ap200));
2904+
EXPECT_EQ(APIntOps::RoundingSDiv(Ap100 + Ap200, A2, APInt::Rounding::DOWN),
2905+
APIntOps::avgFloorS(Ap100, Ap200));
2906+
EXPECT_EQ(APIntOps::RoundingSDiv(Ap100 + Ap200, A2, APInt::Rounding::UP),
2907+
APIntOps::avgCeilS(Ap100, Ap200));
2908+
2909+
EXPECT_EQ(APInt(32, -150), APIntOps::avgFloorS(Am100, Am200));
2910+
EXPECT_EQ(APIntOps::RoundingSDiv(Am100 + Am200, A2, APInt::Rounding::DOWN),
2911+
APIntOps::avgFloorS(Am100, Am200));
2912+
EXPECT_EQ(APIntOps::RoundingSDiv(Am100 + Am200, A2, APInt::Rounding::UP),
2913+
APIntOps::avgCeilS(Am100, Am200));
2914+
2915+
EXPECT_EQ(APInt(32, +100), APIntOps::avgFloorS(Ap100, Ap101));
2916+
EXPECT_EQ(APIntOps::RoundingSDiv(Ap100 + Ap101, A2, APInt::Rounding::DOWN),
2917+
APIntOps::avgFloorS(Ap100, Ap101));
2918+
EXPECT_EQ(APInt(32, +101), APIntOps::avgCeilS(Ap100, Ap101));
2919+
EXPECT_EQ(APIntOps::RoundingSDiv(Ap100 + Ap101, A2, APInt::Rounding::UP),
2920+
APIntOps::avgCeilS(Ap100, Ap101));
2921+
2922+
EXPECT_EQ(APInt(32, -101), APIntOps::avgFloorS(Am100, Am101));
2923+
EXPECT_EQ(APIntOps::RoundingSDiv(Am100 + Am101, A2, APInt::Rounding::DOWN),
2924+
APIntOps::avgFloorS(Am100, Am101));
2925+
EXPECT_EQ(APInt(32, -100), APIntOps::avgCeilS(Am100, Am101));
2926+
EXPECT_EQ(APIntOps::RoundingSDiv(Am100 + Am101, A2, APInt::Rounding::UP),
2927+
APIntOps::avgCeilS(Am100, Am101));
2928+
}
2929+
28802930
TEST(APIntTest, umul_ov) {
28812931
const std::pair<uint64_t, uint64_t> Overflows[] = {
28822932
{0x8000000000000000, 2},

0 commit comments

Comments
 (0)