From 5721fbdfd2efc0b1ac150863c12548e6366d99f6 Mon Sep 17 00:00:00 2001 From: Pedro Lobo Date: Wed, 13 Aug 2025 12:51:44 +0100 Subject: [PATCH 1/4] [ADT] Add signed and unsigned mulx to APInt Adds `mulxs` and `mulxu` methods to `APInt`. These are based on the `MULDQ` and `MULUDQ` x86 intrinsics. --- llvm/include/llvm/ADT/APInt.h | 6 ++++++ llvm/lib/Support/APInt.cpp | 16 ++++++++++++++++ llvm/unittests/ADT/APIntTest.cpp | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h index 295506393a1c4..077d1926e7f35 100644 --- a/llvm/include/llvm/ADT/APInt.h +++ b/llvm/include/llvm/ADT/APInt.h @@ -2294,6 +2294,12 @@ LLVM_ABI APInt mulhs(const APInt &C1, const APInt &C2); /// Returns the high N bits of the multiplication result. LLVM_ABI APInt mulhu(const APInt &C1, const APInt &C2); +/// Performs (2*N)-bit multiplication on sign-extended operands. +LLVM_ABI APInt mulxs(const APInt &C1, const APInt &C2); + +/// Performs (2*N)-bit multiplication on zero-extended operands. +LLVM_ABI APInt mulxu(const APInt &C1, const APInt &C2); + /// Compute X^N for N>=0. /// 0^0 is supported and returns 1. LLVM_ABI APInt pow(const APInt &X, int64_t N); diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp index 954af7fff92a8..5902bb0449868 100644 --- a/llvm/lib/Support/APInt.cpp +++ b/llvm/lib/Support/APInt.cpp @@ -3136,6 +3136,22 @@ APInt APIntOps::mulhu(const APInt &C1, const APInt &C2) { return (C1Ext * C2Ext).extractBits(C1.getBitWidth(), C1.getBitWidth()); } +APInt APIntOps::mulxs(const APInt &C1, const APInt &C2) { + assert(C1.getBitWidth() == C2.getBitWidth() && "Unequal bitwidths"); + unsigned FullWidth = C1.getBitWidth() * 2; + APInt C1Ext = C1.sext(FullWidth); + APInt C2Ext = C2.sext(FullWidth); + return C1Ext * C2Ext; +} + +APInt APIntOps::mulxu(const APInt &C1, const APInt &C2) { + assert(C1.getBitWidth() == C2.getBitWidth() && "Unequal bitwidths"); + unsigned FullWidth = C1.getBitWidth() * 2; + APInt C1Ext = C1.zext(FullWidth); + APInt C2Ext = C2.zext(FullWidth); + return C1Ext * C2Ext; +} + APInt APIntOps::pow(const APInt &X, int64_t N) { assert(N >= 0 && "negative exponents not supported."); APInt Acc = APInt(X.getBitWidth(), 1); diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp index 4741c7bcc140f..d68ae339d1575 100644 --- a/llvm/unittests/ADT/APIntTest.cpp +++ b/llvm/unittests/ADT/APIntTest.cpp @@ -3103,6 +3103,38 @@ TEST(APIntOpsTest, Mulh) { EXPECT_EQ(APInt(128, "FFEB498812C66C68D4552DB89B8EBF8F", 16), i128Res); } +TEST(APIntOpsTest, mulx) { + APInt u32a(32, 0x0001'E235); + APInt u32b(32, 0xF623'55AD); + EXPECT_EQ(0x0001'CFA1'7CA0'76D1, APIntOps::mulxu(u32a, u32b)); + + APInt u64a(64, 0x1234'5678'90AB'CDEF); + APInt u64b(64, 0xFEDC'BA09'8765'4321); + EXPECT_EQ(APInt(128, "121FA000A3723A57C24A442FE55618CF", 16), APIntOps::mulxu(u64a, u64b)); + + APInt u128a(128, "1234567890ABCDEF1234567890ABCDEF", 16); + APInt u128b(128, "FEDCBA0987654321FEDCBA0987654321", 16); + EXPECT_EQ(APInt(256, "121FA000A3723A57E68984312C3A8D7E96B428606E1E6BF5C24A442FE55618CF", 16), APIntOps::mulxu(u128a, u128b)); + + APInt s32a(32, 0x1234'5678); + APInt s32b(32, 0x10AB'CDEF); + APInt s32c(32, 0xFEDC'BA09); + EXPECT_EQ(0x012F'7D02'2A42'D208, APIntOps::mulxs(s32a, s32b)); + EXPECT_EQ(0xFFEB'4988'09CA'3A38, APIntOps::mulxs(s32a, s32c)); + + APInt s64a(64, 0x1234'5678'90AB'CDEF); + APInt s64b(64, 0x1234'5678'90FE'DCBA); + APInt s64c(64, 0xFEDC'BA09'8765'4321); + EXPECT_EQ(APInt(128, "014B66DC328E10C1FB99704184EF03A6", 16), APIntOps::mulxs(s64a, s64b)); + EXPECT_EQ(APInt(128, "FFEB498812C66C68C24A442FE55618CF", 16), APIntOps::mulxs(s64a, s64c)); + + APInt s128a(128, "1234567890ABCDEF1234567890ABCDEF", 16); + APInt s128b(128, "1234567890FEDCBA1234567890FEDCBA", 16); + APInt s128c(128, "FEDCBA0987654321FEDCBA0987654321", 16); + EXPECT_EQ(APInt(256, "014B66DC328E10C1FE303DF9EA0B2529F87E475F3C6C180DFB99704184EF03A6", 16), APIntOps::mulxs(s128a, s128b)); + EXPECT_EQ(APInt(256, "FFEB498812C66C68D4552DB89B8EBF8F96B428606E1E6BF5C24A442FE55618CF", 16), APIntOps::mulxs(s128a, s128c)); +} + TEST(APIntTest, RoundingUDiv) { for (uint64_t Ai = 1; Ai <= 255; Ai++) { APInt A(8, Ai); From 1115cbc301e2a9c2d389f597d8c8d70e29b68532 Mon Sep 17 00:00:00 2001 From: Pedro Lobo Date: Wed, 13 Aug 2025 13:05:39 +0100 Subject: [PATCH 2/4] fix formatting --- llvm/unittests/ADT/APIntTest.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp index d68ae339d1575..e7e2496ece22b 100644 --- a/llvm/unittests/ADT/APIntTest.cpp +++ b/llvm/unittests/ADT/APIntTest.cpp @@ -3110,11 +3110,16 @@ TEST(APIntOpsTest, mulx) { APInt u64a(64, 0x1234'5678'90AB'CDEF); APInt u64b(64, 0xFEDC'BA09'8765'4321); - EXPECT_EQ(APInt(128, "121FA000A3723A57C24A442FE55618CF", 16), APIntOps::mulxu(u64a, u64b)); + EXPECT_EQ(APInt(128, "121FA000A3723A57C24A442FE55618CF", 16), + APIntOps::mulxu(u64a, u64b)); APInt u128a(128, "1234567890ABCDEF1234567890ABCDEF", 16); APInt u128b(128, "FEDCBA0987654321FEDCBA0987654321", 16); - EXPECT_EQ(APInt(256, "121FA000A3723A57E68984312C3A8D7E96B428606E1E6BF5C24A442FE55618CF", 16), APIntOps::mulxu(u128a, u128b)); + EXPECT_EQ( + APInt(256, + "121FA000A3723A57E68984312C3A8D7E96B428606E1E6BF5C24A442FE55618CF", + 16), + APIntOps::mulxu(u128a, u128b)); APInt s32a(32, 0x1234'5678); APInt s32b(32, 0x10AB'CDEF); @@ -3125,14 +3130,24 @@ TEST(APIntOpsTest, mulx) { APInt s64a(64, 0x1234'5678'90AB'CDEF); APInt s64b(64, 0x1234'5678'90FE'DCBA); APInt s64c(64, 0xFEDC'BA09'8765'4321); - EXPECT_EQ(APInt(128, "014B66DC328E10C1FB99704184EF03A6", 16), APIntOps::mulxs(s64a, s64b)); - EXPECT_EQ(APInt(128, "FFEB498812C66C68C24A442FE55618CF", 16), APIntOps::mulxs(s64a, s64c)); + EXPECT_EQ(APInt(128, "014B66DC328E10C1FB99704184EF03A6", 16), + APIntOps::mulxs(s64a, s64b)); + EXPECT_EQ(APInt(128, "FFEB498812C66C68C24A442FE55618CF", 16), + APIntOps::mulxs(s64a, s64c)); APInt s128a(128, "1234567890ABCDEF1234567890ABCDEF", 16); APInt s128b(128, "1234567890FEDCBA1234567890FEDCBA", 16); APInt s128c(128, "FEDCBA0987654321FEDCBA0987654321", 16); - EXPECT_EQ(APInt(256, "014B66DC328E10C1FE303DF9EA0B2529F87E475F3C6C180DFB99704184EF03A6", 16), APIntOps::mulxs(s128a, s128b)); - EXPECT_EQ(APInt(256, "FFEB498812C66C68D4552DB89B8EBF8F96B428606E1E6BF5C24A442FE55618CF", 16), APIntOps::mulxs(s128a, s128c)); + EXPECT_EQ( + APInt(256, + "014B66DC328E10C1FE303DF9EA0B2529F87E475F3C6C180DFB99704184EF03A6", + 16), + APIntOps::mulxs(s128a, s128b)); + EXPECT_EQ( + APInt(256, + "FFEB498812C66C68D4552DB89B8EBF8F96B428606E1E6BF5C24A442FE55618CF", + 16), + APIntOps::mulxs(s128a, s128c)); } TEST(APIntTest, RoundingUDiv) { From d7c843b999784653dda8e28f1e5484bbe2233045 Mon Sep 17 00:00:00 2001 From: Pedro Lobo Date: Wed, 13 Aug 2025 16:39:41 +0100 Subject: [PATCH 3/4] change method names --- llvm/include/llvm/ADT/APInt.h | 4 ++-- llvm/lib/Support/APInt.cpp | 4 ++-- llvm/unittests/ADT/APIntTest.cpp | 20 ++++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h index 077d1926e7f35..d1da47aa335a7 100644 --- a/llvm/include/llvm/ADT/APInt.h +++ b/llvm/include/llvm/ADT/APInt.h @@ -2295,10 +2295,10 @@ LLVM_ABI APInt mulhs(const APInt &C1, const APInt &C2); LLVM_ABI APInt mulhu(const APInt &C1, const APInt &C2); /// Performs (2*N)-bit multiplication on sign-extended operands. -LLVM_ABI APInt mulxs(const APInt &C1, const APInt &C2); +LLVM_ABI APInt mulsi_extended(const APInt &C1, const APInt &C2); /// Performs (2*N)-bit multiplication on zero-extended operands. -LLVM_ABI APInt mulxu(const APInt &C1, const APInt &C2); +LLVM_ABI APInt mului_extended(const APInt &C1, const APInt &C2); /// Compute X^N for N>=0. /// 0^0 is supported and returns 1. diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp index 5902bb0449868..e170c223282a9 100644 --- a/llvm/lib/Support/APInt.cpp +++ b/llvm/lib/Support/APInt.cpp @@ -3136,7 +3136,7 @@ APInt APIntOps::mulhu(const APInt &C1, const APInt &C2) { return (C1Ext * C2Ext).extractBits(C1.getBitWidth(), C1.getBitWidth()); } -APInt APIntOps::mulxs(const APInt &C1, const APInt &C2) { +APInt APIntOps::mulsi_extended(const APInt &C1, const APInt &C2) { assert(C1.getBitWidth() == C2.getBitWidth() && "Unequal bitwidths"); unsigned FullWidth = C1.getBitWidth() * 2; APInt C1Ext = C1.sext(FullWidth); @@ -3144,7 +3144,7 @@ APInt APIntOps::mulxs(const APInt &C1, const APInt &C2) { return C1Ext * C2Ext; } -APInt APIntOps::mulxu(const APInt &C1, const APInt &C2) { +APInt APIntOps::mului_extended(const APInt &C1, const APInt &C2) { assert(C1.getBitWidth() == C2.getBitWidth() && "Unequal bitwidths"); unsigned FullWidth = C1.getBitWidth() * 2; APInt C1Ext = C1.zext(FullWidth); diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp index e7e2496ece22b..7af01859c368a 100644 --- a/llvm/unittests/ADT/APIntTest.cpp +++ b/llvm/unittests/ADT/APIntTest.cpp @@ -3103,15 +3103,15 @@ TEST(APIntOpsTest, Mulh) { EXPECT_EQ(APInt(128, "FFEB498812C66C68D4552DB89B8EBF8F", 16), i128Res); } -TEST(APIntOpsTest, mulx) { +TEST(APIntOpsTest, muli) { APInt u32a(32, 0x0001'E235); APInt u32b(32, 0xF623'55AD); - EXPECT_EQ(0x0001'CFA1'7CA0'76D1, APIntOps::mulxu(u32a, u32b)); + EXPECT_EQ(0x0001'CFA1'7CA0'76D1, APIntOps::mului_extended(u32a, u32b)); APInt u64a(64, 0x1234'5678'90AB'CDEF); APInt u64b(64, 0xFEDC'BA09'8765'4321); EXPECT_EQ(APInt(128, "121FA000A3723A57C24A442FE55618CF", 16), - APIntOps::mulxu(u64a, u64b)); + APIntOps::mului_extended(u64a, u64b)); APInt u128a(128, "1234567890ABCDEF1234567890ABCDEF", 16); APInt u128b(128, "FEDCBA0987654321FEDCBA0987654321", 16); @@ -3119,21 +3119,21 @@ TEST(APIntOpsTest, mulx) { APInt(256, "121FA000A3723A57E68984312C3A8D7E96B428606E1E6BF5C24A442FE55618CF", 16), - APIntOps::mulxu(u128a, u128b)); + APIntOps::mului_extended(u128a, u128b)); APInt s32a(32, 0x1234'5678); APInt s32b(32, 0x10AB'CDEF); APInt s32c(32, 0xFEDC'BA09); - EXPECT_EQ(0x012F'7D02'2A42'D208, APIntOps::mulxs(s32a, s32b)); - EXPECT_EQ(0xFFEB'4988'09CA'3A38, APIntOps::mulxs(s32a, s32c)); + EXPECT_EQ(0x012F'7D02'2A42'D208, APIntOps::mulsi_extended(s32a, s32b)); + EXPECT_EQ(0xFFEB'4988'09CA'3A38, APIntOps::mulsi_extended(s32a, s32c)); APInt s64a(64, 0x1234'5678'90AB'CDEF); APInt s64b(64, 0x1234'5678'90FE'DCBA); APInt s64c(64, 0xFEDC'BA09'8765'4321); EXPECT_EQ(APInt(128, "014B66DC328E10C1FB99704184EF03A6", 16), - APIntOps::mulxs(s64a, s64b)); + APIntOps::mulsi_extended(s64a, s64b)); EXPECT_EQ(APInt(128, "FFEB498812C66C68C24A442FE55618CF", 16), - APIntOps::mulxs(s64a, s64c)); + APIntOps::mulsi_extended(s64a, s64c)); APInt s128a(128, "1234567890ABCDEF1234567890ABCDEF", 16); APInt s128b(128, "1234567890FEDCBA1234567890FEDCBA", 16); @@ -3142,12 +3142,12 @@ TEST(APIntOpsTest, mulx) { APInt(256, "014B66DC328E10C1FE303DF9EA0B2529F87E475F3C6C180DFB99704184EF03A6", 16), - APIntOps::mulxs(s128a, s128b)); + APIntOps::mulsi_extended(s128a, s128b)); EXPECT_EQ( APInt(256, "FFEB498812C66C68D4552DB89B8EBF8F96B428606E1E6BF5C24A442FE55618CF", 16), - APIntOps::mulxs(s128a, s128c)); + APIntOps::mulsi_extended(s128a, s128c)); } TEST(APIntTest, RoundingUDiv) { From 1956194f150bca10bd4b92c1532b2e6225804024 Mon Sep 17 00:00:00 2001 From: Pedro Lobo Date: Wed, 13 Aug 2025 17:34:15 +0100 Subject: [PATCH 4/4] remove `i` from method names --- llvm/include/llvm/ADT/APInt.h | 4 ++-- llvm/lib/Support/APInt.cpp | 4 ++-- llvm/unittests/ADT/APIntTest.cpp | 18 +++++++++--------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h index d1da47aa335a7..4d60ad4459ad6 100644 --- a/llvm/include/llvm/ADT/APInt.h +++ b/llvm/include/llvm/ADT/APInt.h @@ -2295,10 +2295,10 @@ LLVM_ABI APInt mulhs(const APInt &C1, const APInt &C2); LLVM_ABI APInt mulhu(const APInt &C1, const APInt &C2); /// Performs (2*N)-bit multiplication on sign-extended operands. -LLVM_ABI APInt mulsi_extended(const APInt &C1, const APInt &C2); +LLVM_ABI APInt mulsExtended(const APInt &C1, const APInt &C2); /// Performs (2*N)-bit multiplication on zero-extended operands. -LLVM_ABI APInt mului_extended(const APInt &C1, const APInt &C2); +LLVM_ABI APInt muluExtended(const APInt &C1, const APInt &C2); /// Compute X^N for N>=0. /// 0^0 is supported and returns 1. diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp index e170c223282a9..1547f48bc7ac0 100644 --- a/llvm/lib/Support/APInt.cpp +++ b/llvm/lib/Support/APInt.cpp @@ -3136,7 +3136,7 @@ APInt APIntOps::mulhu(const APInt &C1, const APInt &C2) { return (C1Ext * C2Ext).extractBits(C1.getBitWidth(), C1.getBitWidth()); } -APInt APIntOps::mulsi_extended(const APInt &C1, const APInt &C2) { +APInt APIntOps::mulsExtended(const APInt &C1, const APInt &C2) { assert(C1.getBitWidth() == C2.getBitWidth() && "Unequal bitwidths"); unsigned FullWidth = C1.getBitWidth() * 2; APInt C1Ext = C1.sext(FullWidth); @@ -3144,7 +3144,7 @@ APInt APIntOps::mulsi_extended(const APInt &C1, const APInt &C2) { return C1Ext * C2Ext; } -APInt APIntOps::mului_extended(const APInt &C1, const APInt &C2) { +APInt APIntOps::muluExtended(const APInt &C1, const APInt &C2) { assert(C1.getBitWidth() == C2.getBitWidth() && "Unequal bitwidths"); unsigned FullWidth = C1.getBitWidth() * 2; APInt C1Ext = C1.zext(FullWidth); diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp index 7af01859c368a..acc6a09acbf4d 100644 --- a/llvm/unittests/ADT/APIntTest.cpp +++ b/llvm/unittests/ADT/APIntTest.cpp @@ -3106,12 +3106,12 @@ TEST(APIntOpsTest, Mulh) { TEST(APIntOpsTest, muli) { APInt u32a(32, 0x0001'E235); APInt u32b(32, 0xF623'55AD); - EXPECT_EQ(0x0001'CFA1'7CA0'76D1, APIntOps::mului_extended(u32a, u32b)); + EXPECT_EQ(0x0001'CFA1'7CA0'76D1, APIntOps::muluExtended(u32a, u32b)); APInt u64a(64, 0x1234'5678'90AB'CDEF); APInt u64b(64, 0xFEDC'BA09'8765'4321); EXPECT_EQ(APInt(128, "121FA000A3723A57C24A442FE55618CF", 16), - APIntOps::mului_extended(u64a, u64b)); + APIntOps::muluExtended(u64a, u64b)); APInt u128a(128, "1234567890ABCDEF1234567890ABCDEF", 16); APInt u128b(128, "FEDCBA0987654321FEDCBA0987654321", 16); @@ -3119,21 +3119,21 @@ TEST(APIntOpsTest, muli) { APInt(256, "121FA000A3723A57E68984312C3A8D7E96B428606E1E6BF5C24A442FE55618CF", 16), - APIntOps::mului_extended(u128a, u128b)); + APIntOps::muluExtended(u128a, u128b)); APInt s32a(32, 0x1234'5678); APInt s32b(32, 0x10AB'CDEF); APInt s32c(32, 0xFEDC'BA09); - EXPECT_EQ(0x012F'7D02'2A42'D208, APIntOps::mulsi_extended(s32a, s32b)); - EXPECT_EQ(0xFFEB'4988'09CA'3A38, APIntOps::mulsi_extended(s32a, s32c)); + EXPECT_EQ(0x012F'7D02'2A42'D208, APIntOps::mulsExtended(s32a, s32b)); + EXPECT_EQ(0xFFEB'4988'09CA'3A38, APIntOps::mulsExtended(s32a, s32c)); APInt s64a(64, 0x1234'5678'90AB'CDEF); APInt s64b(64, 0x1234'5678'90FE'DCBA); APInt s64c(64, 0xFEDC'BA09'8765'4321); EXPECT_EQ(APInt(128, "014B66DC328E10C1FB99704184EF03A6", 16), - APIntOps::mulsi_extended(s64a, s64b)); + APIntOps::mulsExtended(s64a, s64b)); EXPECT_EQ(APInt(128, "FFEB498812C66C68C24A442FE55618CF", 16), - APIntOps::mulsi_extended(s64a, s64c)); + APIntOps::mulsExtended(s64a, s64c)); APInt s128a(128, "1234567890ABCDEF1234567890ABCDEF", 16); APInt s128b(128, "1234567890FEDCBA1234567890FEDCBA", 16); @@ -3142,12 +3142,12 @@ TEST(APIntOpsTest, muli) { APInt(256, "014B66DC328E10C1FE303DF9EA0B2529F87E475F3C6C180DFB99704184EF03A6", 16), - APIntOps::mulsi_extended(s128a, s128b)); + APIntOps::mulsExtended(s128a, s128b)); EXPECT_EQ( APInt(256, "FFEB498812C66C68D4552DB89B8EBF8F96B428606E1E6BF5C24A442FE55618CF", 16), - APIntOps::mulsi_extended(s128a, s128c)); + APIntOps::mulsExtended(s128a, s128c)); } TEST(APIntTest, RoundingUDiv) {