[flang-commits] [flang] [Flang] Shift the data from lower to higher order bits in the big endian environment (PR #73670)

via flang-commits flang-commits at lists.llvm.org
Thu Dec 28 15:02:22 PST 2023


https://github.com/madanial0 updated https://github.com/llvm/llvm-project/pull/73670

>From e5639ec192c3b6482ab75e54f96714cee4317de7 Mon Sep 17 00:00:00 2001
From: Mark Danial <madanial at dixon.rtp.raleigh.ibm.com>
Date: Mon, 27 Nov 2023 21:11:52 -0500
Subject: [PATCH 1/4] [Flang] Shift the data from lower to higher order bits in
 the big endian environment

---
 flang/runtime/edit-input.cpp | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp
index 2b809749067772..9ebb9965bf9ead 100644
--- a/flang/runtime/edit-input.cpp
+++ b/flang/runtime/edit-input.cpp
@@ -244,7 +244,15 @@ bool EditIntegerInput(
     value = -value;
   }
   if (any || !io.GetConnectionState().IsAtEOF()) {
-    std::memcpy(n, &value, kind); // a blank field means zero
+    // For integer kind <= 4, the value is stored in the lower order bits on
+    // the big endian platform. When memcpy the value, shift the value, shift
+    // the value to the higher order bit.
+    if (!isHostLittleEndian && kind <= 4) {
+      auto l{value.low() << (8 * (sizeof(value.low()) - kind))};
+      std::memcpy(n, &l, kind);
+    } else {
+      std::memcpy(n, &value, kind); // a blank field means zero
+    }
   }
   return any;
 }

>From 0c25a347266aa4aa43b1276cfde3a4b45b001574 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Tue, 12 Dec 2023 15:56:33 -0500
Subject: [PATCH 2/4] swap two halves in Int128 in big endian

---
 flang/include/flang/Common/uint128.h | 30 ++++++++++++++++++++--------
 flang/runtime/edit-input.cpp         | 10 +++++-----
 2 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/flang/include/flang/Common/uint128.h b/flang/include/flang/Common/uint128.h
index bfd2eef01f6f08..c66dc4f303a734 100644
--- a/flang/include/flang/Common/uint128.h
+++ b/flang/include/flang/Common/uint128.h
@@ -23,6 +23,16 @@
 #include <cstdint>
 #include <type_traits>
 
+#if FLANG_LITTLE_ENDIAN
+#define SWAP(a, i, b, j) \
+  a{i}, b { j }
+#elif FLANG_BIG_ENDIAN
+#define SWAP(a, i, b, j) \
+  b{j}, a { i }
+#else
+#error host endianness is not known
+#endif
+
 namespace Fortran::common {
 
 template <bool IS_SIGNED = false> class Int128 {
@@ -34,14 +44,14 @@ template <bool IS_SIGNED = false> class Int128 {
   constexpr Int128(unsigned long n) : low_{n} {}
   constexpr Int128(unsigned long long n) : low_{n} {}
   constexpr Int128(int n)
-      : low_{static_cast<std::uint64_t>(n)}, high_{-static_cast<std::uint64_t>(
-                                                 n < 0)} {}
+      : SWAP(low_, static_cast<std::uint64_t>(n), high_,
+            -static_cast<std::uint64_t>(n < 0)) {}
   constexpr Int128(long n)
-      : low_{static_cast<std::uint64_t>(n)}, high_{-static_cast<std::uint64_t>(
-                                                 n < 0)} {}
+      : SWAP(low_, static_cast<std::uint64_t>(n), high_,
+            -static_cast<std::uint64_t>(n < 0)) {}
   constexpr Int128(long long n)
-      : low_{static_cast<std::uint64_t>(n)}, high_{-static_cast<std::uint64_t>(
-                                                 n < 0)} {}
+      : SWAP(low_, static_cast<std::uint64_t>(n), high_,
+            -static_cast<std::uint64_t>(n < 0)) {}
   constexpr Int128(const Int128 &) = default;
   constexpr Int128(Int128 &&) = default;
   constexpr Int128 &operator=(const Int128 &) = default;
@@ -246,7 +256,8 @@ template <bool IS_SIGNED = false> class Int128 {
   }
 
 private:
-  constexpr Int128(std::uint64_t hi, std::uint64_t lo) : low_{lo}, high_{hi} {}
+  constexpr Int128(std::uint64_t hi, std::uint64_t lo)
+      : SWAP(low_, lo, high_, hi) {}
   constexpr int LeadingZeroes() const {
     if (high_ == 0) {
       return 64 + LeadingZeroBitCount(low_);
@@ -255,7 +266,7 @@ template <bool IS_SIGNED = false> class Int128 {
     }
   }
   static constexpr std::uint64_t topBit{std::uint64_t{1} << 63};
-  std::uint64_t low_{0}, high_{0};
+  std::uint64_t SWAP(low_, 0, high_, 0);
 };
 
 using UnsignedInt128 = Int128<false>;
@@ -288,4 +299,7 @@ template <int BITS>
 using HostSignedIntType = typename HostSignedIntTypeHelper<BITS>::type;
 
 } // namespace Fortran::common
+
+#undef SWAP
+
 #endif
diff --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp
index 9ebb9965bf9ead..1e831e11794ac7 100644
--- a/flang/runtime/edit-input.cpp
+++ b/flang/runtime/edit-input.cpp
@@ -244,11 +244,11 @@ bool EditIntegerInput(
     value = -value;
   }
   if (any || !io.GetConnectionState().IsAtEOF()) {
-    // For integer kind <= 4, the value is stored in the lower order bits on
-    // the big endian platform. When memcpy the value, shift the value, shift
-    // the value to the higher order bit.
-    if (!isHostLittleEndian && kind <= 4) {
-      auto l{value.low() << (8 * (sizeof(value.low()) - kind))};
+    // The value is stored in the lower order bits on big endian platform.
+    // When memcpy, shift the value to the higher order bit.
+    auto shft{static_cast<int>(sizeof(value.low())) - kind};
+    if (!isHostLittleEndian && shft >= 0) {
+      auto l{value.low() << (8 * shft)};
       std::memcpy(n, &l, kind);
     } else {
       std::memcpy(n, &value, kind); // a blank field means zero

>From 96a3678473687290780328e5a2b919c24e670e1c Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Mon, 18 Dec 2023 20:54:17 -0500
Subject: [PATCH 3/4] address review comments

---
 flang/include/flang/Common/uint128.h | 48 +++++++++++++---------------
 1 file changed, 23 insertions(+), 25 deletions(-)

diff --git a/flang/include/flang/Common/uint128.h b/flang/include/flang/Common/uint128.h
index c66dc4f303a734..03e44eb6997d5b 100644
--- a/flang/include/flang/Common/uint128.h
+++ b/flang/include/flang/Common/uint128.h
@@ -23,16 +23,6 @@
 #include <cstdint>
 #include <type_traits>
 
-#if FLANG_LITTLE_ENDIAN
-#define SWAP(a, i, b, j) \
-  a{i}, b { j }
-#elif FLANG_BIG_ENDIAN
-#define SWAP(a, i, b, j) \
-  b{j}, a { i }
-#else
-#error host endianness is not known
-#endif
-
 namespace Fortran::common {
 
 template <bool IS_SIGNED = false> class Int128 {
@@ -43,15 +33,18 @@ template <bool IS_SIGNED = false> class Int128 {
   constexpr Int128(unsigned n) : low_{n} {}
   constexpr Int128(unsigned long n) : low_{n} {}
   constexpr Int128(unsigned long long n) : low_{n} {}
-  constexpr Int128(int n)
-      : SWAP(low_, static_cast<std::uint64_t>(n), high_,
-            -static_cast<std::uint64_t>(n < 0)) {}
-  constexpr Int128(long n)
-      : SWAP(low_, static_cast<std::uint64_t>(n), high_,
-            -static_cast<std::uint64_t>(n < 0)) {}
-  constexpr Int128(long long n)
-      : SWAP(low_, static_cast<std::uint64_t>(n), high_,
-            -static_cast<std::uint64_t>(n < 0)) {}
+  constexpr Int128(int n) {
+    low_ = static_cast<std::uint64_t>(n);
+    high_ = -static_cast<std::uint64_t>(n < 0);
+  }
+  constexpr Int128(long n) {
+    low_ = static_cast<std::uint64_t>(n);
+    high_ = -static_cast<std::uint64_t>(n < 0);
+  }
+  constexpr Int128(long long n) {
+    low_ = static_cast<std::uint64_t>(n);
+    high_ = -static_cast<std::uint64_t>(n < 0);
+  }
   constexpr Int128(const Int128 &) = default;
   constexpr Int128(Int128 &&) = default;
   constexpr Int128 &operator=(const Int128 &) = default;
@@ -256,8 +249,10 @@ template <bool IS_SIGNED = false> class Int128 {
   }
 
 private:
-  constexpr Int128(std::uint64_t hi, std::uint64_t lo)
-      : SWAP(low_, lo, high_, hi) {}
+  constexpr Int128(std::uint64_t hi, std::uint64_t lo) {
+    low_ = lo;
+    high_ = hi;
+  }
   constexpr int LeadingZeroes() const {
     if (high_ == 0) {
       return 64 + LeadingZeroBitCount(low_);
@@ -266,7 +261,13 @@ template <bool IS_SIGNED = false> class Int128 {
     }
   }
   static constexpr std::uint64_t topBit{std::uint64_t{1} << 63};
-  std::uint64_t SWAP(low_, 0, high_, 0);
+#if FLANG_LITTLE_ENDIAN
+  std::uint64_t low_{0}, high_{0};
+#elif FLANG_BIG_ENDIAN
+  std::uint64_t high_{0}, low_{0};
+#else
+#error host endianness is not known
+#endif
 };
 
 using UnsignedInt128 = Int128<false>;
@@ -299,7 +300,4 @@ template <int BITS>
 using HostSignedIntType = typename HostSignedIntTypeHelper<BITS>::type;
 
 } // namespace Fortran::common
-
-#undef SWAP
-
 #endif

>From ef725571764a50b2df3318d2683a6162ac585d33 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Mon, 18 Dec 2023 22:15:44 -0500
Subject: [PATCH 4/4] add comment to explain the logic

---
 flang/runtime/edit-input.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp
index 1e831e11794ac7..c4fa186e289db2 100644
--- a/flang/runtime/edit-input.cpp
+++ b/flang/runtime/edit-input.cpp
@@ -247,6 +247,7 @@ bool EditIntegerInput(
     // The value is stored in the lower order bits on big endian platform.
     // When memcpy, shift the value to the higher order bit.
     auto shft{static_cast<int>(sizeof(value.low())) - kind};
+    // For kind==8 (i.e. shft==0), the value is stored in low_ in big endian.
     if (!isHostLittleEndian && shft >= 0) {
       auto l{value.low() << (8 * shft)};
       std::memcpy(n, &l, kind);



More information about the flang-commits mailing list