Gabe Black has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/42358 )

Change subject: base: Create wide multiply functions in intmath.hh.
......................................................................

base: Create wide multiply functions in intmath.hh.

These implementations are from the x86 multiply microops. When
multipying two integers of a certain width together, these functions
will produce two values of the same size which hold the upper and lower
part of the multiplication result.

The version which works for 32 bit values and smaller just takes
advantage of 64 bit multiplication using standard types. The 64 bit
version needs to do more work since there isn't a built in standard
facility for doing those sorts of multiplications.

Change-Id: If7b3d3aa174dd13aae6f383772cbc5291181de5d
---
M src/base/intmath.hh
M src/base/intmath.test.cc
2 files changed, 121 insertions(+), 0 deletions(-)



diff --git a/src/base/intmath.hh b/src/base/intmath.hh
index acf7681..8c88ae7 100644
--- a/src/base/intmath.hh
+++ b/src/base/intmath.hh
@@ -117,6 +117,83 @@
 }

 /**
+ * @ingroup api_base_utils
+ * Multiply two values Aa and Bb where Aa = A << p + a.
+ *   Aa * Bb
+ * = (A << p + a) * (B << p + b)
+ * = (A * B) << 2p + (A * b + a * B) << p + a * b
+ */
+template <typename T>
+static constexpr std::enable_if_t<sizeof(T) <= sizeof(uint32_t)>
+mulUnsigned(std::make_unsigned_t<T> &hi, std::make_unsigned_t<T> &low,
+            std::make_unsigned_t<T> val_a, std::make_unsigned_t<T> val_b)
+{
+    uint64_t product = (uint64_t)val_a * (uint64_t)val_b;
+    low = product;
+    hi = (product >> (sizeof(low) * 8));
+};
+
+template <typename T>
+static constexpr std::enable_if_t<sizeof(T) <= sizeof(uint32_t)>
+mulSigned(std::make_signed_t<T> &hi, std::make_signed_t<T> &low,
+          std::make_signed_t<T> val_a, std::make_signed_t<T> val_b)
+{
+    uint64_t product = (int64_t)val_a * (int64_t)val_b;
+    low = product;
+    hi = (product >> (sizeof(low) * 8));
+};
+
+template <typename T>
+static constexpr std::enable_if_t<sizeof(T) == sizeof(uint64_t)>
+mulUnsigned(std::make_unsigned_t<T> &hi, std::make_unsigned_t<T> &low,
+            std::make_unsigned_t<T> val_a, std::make_unsigned_t<T> val_b)
+{
+    low = val_a * val_b;
+
+    uint64_t A = (uint32_t)(val_a >> 32);
+    uint64_t a = (uint32_t)val_a;
+    uint64_t B = (uint32_t)(val_b >> 32);
+    uint64_t b = (uint32_t)val_b;
+
+    uint64_t c1, c2; // Carry between place values.
+    uint64_t ab = a * b, Ab = A * b, aB = a * B, AB = A * B;
+
+    c1 = (uint32_t)(ab >> 32);
+
+    // Be careful to avoid overflow.
+    c2 = (c1 >> 1) + (Ab >> 1) + (aB >> 1);
+    c2 += ((c1 & 0x1) + (Ab & 0x1) + (aB & 0x1)) >> 1;
+    c2 >>= 31;
+
+    hi = AB + c2;
+}
+
+template <typename T>
+static constexpr std::enable_if_t<sizeof(T) == sizeof(uint64_t)>
+mulSigned(std::make_signed_t<T> &hi, std::make_signed_t<T> &low,
+          std::make_signed_t<T> val_a, std::make_signed_t<T> val_b)
+{
+    uint64_t u_hi, u_low;
+    mulUnsigned<T>(u_hi, u_low, val_a, val_b);
+
+    if (val_a < 0)
+        u_hi -= val_b;
+    if (val_b < 0)
+        u_hi -= val_a;
+
+    hi = u_hi;
+    low = u_low;
+}
+
+/**
+ * @ingroup api_base_utils
+ */
+static constexpr void
+mulSigned(uint64_t &hi, uint64_t &low, uint64_t a, uint64_t b)
+{
+}
+
+/**
  * This function is used to align addresses in memory.
  *
  * @param val is the address to be aligned.
diff --git a/src/base/intmath.test.cc b/src/base/intmath.test.cc
index e985a1b..55d3e71 100644
--- a/src/base/intmath.test.cc
+++ b/src/base/intmath.test.cc
@@ -108,6 +108,50 @@
     EXPECT_EQ(46, divCeil(451, 10));
 }

+TEST(IntmathTest, mulUnsignedNarrow)
+{
+    uint8_t a = 0xff;
+    uint8_t b = 0x02;
+    uint8_t hi;
+    uint8_t low;
+    mulUnsigned<uint8_t>(hi, low, a, b);
+    EXPECT_EQ(hi, 0x1);
+    EXPECT_EQ(low, 0xfe);
+}
+
+TEST(IntmathTest, mulSignedNarrow)
+{
+    int8_t a = -0x80;
+    int8_t b = -0x7f;
+    int8_t hi;
+    int8_t low;
+    mulSigned<int8_t>(hi, low, a, b);
+    EXPECT_EQ(hi, 0x3f);
+    EXPECT_EQ(low, -0x80);
+}
+
+TEST(IntmathTest, mulUnsignedWide)
+{
+    uint64_t a = 0xffffffffffffffffULL;
+    uint64_t b = 0x0000000000000002ULL;
+    uint64_t hi;
+    uint64_t low;
+    mulUnsigned<uint64_t>(hi, low, a, b);
+    EXPECT_EQ(hi, 0x1);
+    EXPECT_EQ(low, 0xfffffffffffffffe);
+}
+
+TEST(IntMathTest, mulSignedWide)
+{
+    int64_t a = -0x8000000000000000;
+    int64_t b = -0x7fffffffffffffff;
+    int64_t hi;
+    int64_t low;
+    mulSigned<int64_t>(hi, low, a, b);
+    EXPECT_EQ(hi, 0x3fffffffffffffff);
+    EXPECT_EQ(low, -0x8000000000000000);
+}
+
 TEST(IntmathTest, roundUp)
 {
     EXPECT_EQ(4104, roundUp(4101, 4));

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/42358
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: If7b3d3aa174dd13aae6f383772cbc5291181de5d
Gerrit-Change-Number: 42358
Gerrit-PatchSet: 1
Gerrit-Owner: Gabe Black <gabe.bl...@gmail.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s

Reply via email to