Bug#835823: Polly's imath assumes little-endian

James Clarke jrtc27 at jrtc27.com
Sun Aug 28 16:26:02 UTC 2016


Source: llvm-toolchain-3.8
Version: 1:3.8.1-9
Tags: patch
Control: clone -1 -2 -3
Control: reassign -2 llvm-toolchain-3.9 1:3.9~+rc3-1
Control: reassign -3 llvm-toolchain-snapshot 1:4.0~svn279916-1

Hi,
The bundled copy of imath currently assumes little-endian in its
mpz_import and mpz_export functions (which provide a GMP-compatible
interface). I have submitted a pull request to upstream imath[0] which
provides a full implementation with respect to endianness. With this
patch applied to the bundled imath (patch attached with subdirectories
fixed) check-polly succeeds on sparc64 (perhaps you could consider
making check-polly failures fatal on all architectures, and re-enabling
polly on powerpc and s390x?).

Regards,
James

[0] https://github.com/creachadair/imath/pull/12
-------------- next part --------------
--- a/polly/lib/External/isl/imath/gmp_compat.c
+++ b/polly/lib/External/isl/imath/gmp_compat.c
@@ -28,6 +28,7 @@
 #include <assert.h>
 #include <ctype.h>
 #include <string.h>
+#include <stdio.h>
 
 #ifdef  NDEBUG
 #define CHECK(res) (res)
@@ -35,6 +36,12 @@
 #define CHECK(res) assert(((res) == MP_OK) && "expected MP_OK")
 #endif
 
+/* *(signed char *)&endian_test will thus either be:
+ *     0b00000001 =  1 on big-endian
+ *     0b11111111 = -1 on little-endian */
+static const uint16_t endian_test = 0x1FF;
+#define HOST_ENDIAN (*(signed char *)&endian_test)
+
 /*************************************************************************
  *
  * Functions with direct translations
@@ -673,22 +680,19 @@ unsigned long GMPZAPI(fdiv_q_ui)(mp_int q, mp_int n, unsigned long d) {
 
 /* gmp: mpz_export */
 void* GMPZAPI(export)(void *rop, size_t *countp, int order, size_t size, int endian, size_t nails, mp_int op) {
-  int i;
+  int i, j;
   int num_used_bytes;
   size_t num_words, num_missing_bytes;
+  ssize_t word_offset;
   unsigned char* dst;
-  unsigned char* src;
+  mp_digit* src;
+  int src_bits;
 
   /* We do not have a complete implementation. Assert to ensure our
-   * restrictions are in place, We do not support big endian output, but do not
-   * check that native endian is little endian. */
+   * restrictions are in place. */
   assert(nails  == 0 && "Do not support non-full words");
-  assert((endian == 0 || endian == -1) && "Do not support big endian");
-
-  /* The gmp API requires that order must be -1 or 1.
-     Not sure how gmp behaves when order is not 1 or -1, so force all non-one
-     values to -1 for now. */
-  if (order != 1) order = -1;
+  assert(endian == 1 || endian == 0 || endian == -1);
+  assert(order == 1 || order == -1);
 
   /* Test for zero */
   if (mp_int_compare_zero(op) == 0) {
@@ -719,47 +723,32 @@ void* GMPZAPI(export)(void *rop, size_t *countp, int order, size_t size, int end
     rop = malloc(num_words * size);
   }
 
-  /* Initialize dst and src pointers */
-  dst = (unsigned char *)rop;
-  src = (unsigned char *)MP_DIGITS(op);
-
-  /* Most significant word first */
-  if (order == 1) {
-    size_t words_written = 0;
-    src += (num_words-1) * size;
-
-    /* Handle write of first word specially */
-    for (i = 0; i < size - num_missing_bytes; i++)
-      dst[i] = src[i];
-    for (; i < size; i++)
-      dst[i] = 0;
-    dst += size;
-    src -= size;
-    words_written++;
-
-    for (; words_written < num_words; words_written++) {
-      for (i = 0; i < size; i++)
-        dst[i] = src[i];
-      dst += size;
-      src -= size;
-    }
+  if (endian == 0) {
+    endian = HOST_ENDIAN;
   }
-  /* Least significant word first */
-  else {
-    size_t words_written = 0;
-    for (; words_written < num_words - 1; words_written++) {
-      for (i = 0; i < size; i++)
-        dst[i] = src[i];
-      dst += size;
-      src += size;
-    }
 
-    /* Handle write of last word specially */
-    for (i = 0; i < size - num_missing_bytes; i++)
-      dst[i] = src[i];
+  /* Initialize dst and src pointers */
+  dst = (unsigned char *) rop + (order >= 0 ? (num_words-1) * size : 0) + (endian >= 0 ? size-1 : 0);
+  src = MP_DIGITS(op);
+  src_bits = MP_DIGIT_BIT;
+
+  word_offset = (endian >= 0 ? size : -size) + (order < 0 ? size : -size);
 
-    for (; i < size; i++)
-      dst[i] = 0;
+  for (i = 0; i < num_words; i++) {
+    for (j = 0; j < size && i * size + j < num_used_bytes; j++) {
+      if (src_bits == 0) {
+        ++src;
+        src_bits = MP_DIGIT_BIT;
+      }
+      *dst = (*src >> (MP_DIGIT_BIT - src_bits)) & 0xFF;
+      src_bits -= 8;
+      dst -= endian;
+    }
+    for (; j < size; j++) {
+      *dst = 0;
+      dst -= endian;
+    }
+    dst += word_offset;
   }
 
   if (countp)
@@ -773,17 +762,23 @@ void GMPZAPI(import)(mp_int rop, size_t count, int order, size_t size, int endia
   mp_int tmp = &tmpz;
   size_t total_size;
   size_t num_digits;
-  const char *src;
-  char *dst;
-  int i;
+  ssize_t word_offset;
+  const unsigned char *src;
+  mp_digit *dst;
+  int dst_bits;
+  int i, j;
   if (count == 0 || op == NULL)
     return;
 
   /* We do not have a complete implementation. Assert to ensure our
-   * restrictions are in place, We do not support big endian output, but do not
-   * check that native endian is little endian. */
+   * restrictions are in place. */
   assert(nails  == 0 && "Do not support non-full words");
-  assert((endian == 0 || endian == -1) && "Do not support big endian");
+  assert(endian == 1 || endian == 0 || endian == -1);
+  assert(order == 1 || order == -1);
+
+  if (endian == 0) {
+    endian = HOST_ENDIAN;
+  }
 
   /* Compute number of needed digits by ceil division */
   total_size = count * size;
@@ -795,30 +790,25 @@ void GMPZAPI(import)(mp_int rop, size_t count, int order, size_t size, int endia
     tmp->digits[i] = 0;
 
   /* Copy bytes */
-  src = (const char *) op;
-  dst = (char *)MP_DIGITS(tmp);
-
-  /* Most significant word is first */
-  if (order == 1) {
-    size_t word;
-    dst += (count - 1) * size;
-    for (word = 0; word < count; word++) {
-      for (i = 0; i < size; i++)
-        dst[i] = src[i];
-      dst -= size;
-      src += size;
-    }
-  }
-  /* Least significant word is first */
-  else {
-    size_t word;
-    for (word = 0; word < count; word++) {
-      for (i = 0; i < size; i++)
-        dst[i] = src[i];
-      dst += size;
-      src += size;
+  src = (const unsigned char *) op + (order >= 0 ? (count-1) * size : 0) + (endian >= 0 ? size-1 : 0);
+  dst = MP_DIGITS(tmp);
+  dst_bits = 0;
+
+  word_offset = (endian >= 0 ? size : -size) + (order < 0 ? size : -size);
+
+  for (i = 0; i < count; i++) {
+    for (j = 0; j < size; j++) {
+      if (dst_bits == MP_DIGIT_BIT) {
+        ++dst;
+        dst_bits = 0;
+      }
+      *dst |= ((mp_digit)*src) << dst_bits;
+      dst_bits += 8;
+      src -= endian;
     }
+    src += word_offset;
   }
+
   MP_USED(tmp) = num_digits;
 
   /* Remove leading zeros from number */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.alioth.debian.org/pipermail/pkg-llvm-team/attachments/20160828/7b518e61/attachment.sig>


More information about the Pkg-llvm-team mailing list