Skip to content

Commit 08eff57

Browse files
authored
[ADT] Add signed and unsigned mulExtended to APInt (#153399)
Adds `mulsExtended` and `muluExtended` methods to `APInt`, as suggested in #153293. These are based on the `MULDQ` and `MULUDQ` x86 intrinsics.
1 parent 7a13a75 commit 08eff57

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed

llvm/include/llvm/ADT/APInt.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2294,6 +2294,12 @@ LLVM_ABI APInt mulhs(const APInt &C1, const APInt &C2);
22942294
/// Returns the high N bits of the multiplication result.
22952295
LLVM_ABI APInt mulhu(const APInt &C1, const APInt &C2);
22962296

2297+
/// Performs (2*N)-bit multiplication on sign-extended operands.
2298+
LLVM_ABI APInt mulsExtended(const APInt &C1, const APInt &C2);
2299+
2300+
/// Performs (2*N)-bit multiplication on zero-extended operands.
2301+
LLVM_ABI APInt muluExtended(const APInt &C1, const APInt &C2);
2302+
22972303
/// Compute X^N for N>=0.
22982304
/// 0^0 is supported and returns 1.
22992305
LLVM_ABI APInt pow(const APInt &X, int64_t N);

llvm/lib/Support/APInt.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3136,6 +3136,22 @@ APInt APIntOps::mulhu(const APInt &C1, const APInt &C2) {
31363136
return (C1Ext * C2Ext).extractBits(C1.getBitWidth(), C1.getBitWidth());
31373137
}
31383138

3139+
APInt APIntOps::mulsExtended(const APInt &C1, const APInt &C2) {
3140+
assert(C1.getBitWidth() == C2.getBitWidth() && "Unequal bitwidths");
3141+
unsigned FullWidth = C1.getBitWidth() * 2;
3142+
APInt C1Ext = C1.sext(FullWidth);
3143+
APInt C2Ext = C2.sext(FullWidth);
3144+
return C1Ext * C2Ext;
3145+
}
3146+
3147+
APInt APIntOps::muluExtended(const APInt &C1, const APInt &C2) {
3148+
assert(C1.getBitWidth() == C2.getBitWidth() && "Unequal bitwidths");
3149+
unsigned FullWidth = C1.getBitWidth() * 2;
3150+
APInt C1Ext = C1.zext(FullWidth);
3151+
APInt C2Ext = C2.zext(FullWidth);
3152+
return C1Ext * C2Ext;
3153+
}
3154+
31393155
APInt APIntOps::pow(const APInt &X, int64_t N) {
31403156
assert(N >= 0 && "negative exponents not supported.");
31413157
APInt Acc = APInt(X.getBitWidth(), 1);

llvm/unittests/ADT/APIntTest.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3103,6 +3103,53 @@ TEST(APIntOpsTest, Mulh) {
31033103
EXPECT_EQ(APInt(128, "FFEB498812C66C68D4552DB89B8EBF8F", 16), i128Res);
31043104
}
31053105

3106+
TEST(APIntOpsTest, muli) {
3107+
APInt u32a(32, 0x0001'E235);
3108+
APInt u32b(32, 0xF623'55AD);
3109+
EXPECT_EQ(0x0001'CFA1'7CA0'76D1, APIntOps::muluExtended(u32a, u32b));
3110+
3111+
APInt u64a(64, 0x1234'5678'90AB'CDEF);
3112+
APInt u64b(64, 0xFEDC'BA09'8765'4321);
3113+
EXPECT_EQ(APInt(128, "121FA000A3723A57C24A442FE55618CF", 16),
3114+
APIntOps::muluExtended(u64a, u64b));
3115+
3116+
APInt u128a(128, "1234567890ABCDEF1234567890ABCDEF", 16);
3117+
APInt u128b(128, "FEDCBA0987654321FEDCBA0987654321", 16);
3118+
EXPECT_EQ(
3119+
APInt(256,
3120+
"121FA000A3723A57E68984312C3A8D7E96B428606E1E6BF5C24A442FE55618CF",
3121+
16),
3122+
APIntOps::muluExtended(u128a, u128b));
3123+
3124+
APInt s32a(32, 0x1234'5678);
3125+
APInt s32b(32, 0x10AB'CDEF);
3126+
APInt s32c(32, 0xFEDC'BA09);
3127+
EXPECT_EQ(0x012F'7D02'2A42'D208, APIntOps::mulsExtended(s32a, s32b));
3128+
EXPECT_EQ(0xFFEB'4988'09CA'3A38, APIntOps::mulsExtended(s32a, s32c));
3129+
3130+
APInt s64a(64, 0x1234'5678'90AB'CDEF);
3131+
APInt s64b(64, 0x1234'5678'90FE'DCBA);
3132+
APInt s64c(64, 0xFEDC'BA09'8765'4321);
3133+
EXPECT_EQ(APInt(128, "014B66DC328E10C1FB99704184EF03A6", 16),
3134+
APIntOps::mulsExtended(s64a, s64b));
3135+
EXPECT_EQ(APInt(128, "FFEB498812C66C68C24A442FE55618CF", 16),
3136+
APIntOps::mulsExtended(s64a, s64c));
3137+
3138+
APInt s128a(128, "1234567890ABCDEF1234567890ABCDEF", 16);
3139+
APInt s128b(128, "1234567890FEDCBA1234567890FEDCBA", 16);
3140+
APInt s128c(128, "FEDCBA0987654321FEDCBA0987654321", 16);
3141+
EXPECT_EQ(
3142+
APInt(256,
3143+
"014B66DC328E10C1FE303DF9EA0B2529F87E475F3C6C180DFB99704184EF03A6",
3144+
16),
3145+
APIntOps::mulsExtended(s128a, s128b));
3146+
EXPECT_EQ(
3147+
APInt(256,
3148+
"FFEB498812C66C68D4552DB89B8EBF8F96B428606E1E6BF5C24A442FE55618CF",
3149+
16),
3150+
APIntOps::mulsExtended(s128a, s128c));
3151+
}
3152+
31063153
TEST(APIntTest, RoundingUDiv) {
31073154
for (uint64_t Ai = 1; Ai <= 255; Ai++) {
31083155
APInt A(8, Ai);

0 commit comments

Comments
 (0)