Fix PR1836: in the interpreter, read and write apints
authorDuncan Sands <baldrick@free.fr>
Mon, 10 Dec 2007 17:43:13 +0000 (17:43 +0000)
committerDuncan Sands <baldrick@free.fr>
Mon, 10 Dec 2007 17:43:13 +0000 (17:43 +0000)
using the minimum possible number of bytes.  For little
endian targets run on little endian machines, apints are
stored in memory from LSB to MSB as before.  For big endian
targets on big endian machines they are stored from MSB to
LSB which wasn't always the case before (if the target and
host endianness doesn't match values are stored according
to the host's endianness).  Doing this requires knowing the
endianness of the host, which is determined when configuring -
thanks go to Anton for this.  Only having access to little
endian machines I was unable to properly test the big endian
part, which is also the most complicated...

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@44796 91177308-0d34-0410-b5e6-96231b3b80d8

autoconf/configure.ac
configure
include/llvm/Config/config.h.in
include/llvm/Target/TargetData.h
lib/ExecutionEngine/ExecutionEngine.cpp
test/ExecutionEngine/2007-12-10-APIntLoadStore.ll [new file with mode: 0644]

index 979e3a89865c84d4c58429765ed1ccf8c9d6f0bd..fe16b5073e4d96a1d7c87bec7f5cf4232d4fe710 100644 (file)
@@ -227,7 +227,10 @@ dnl Define a substitution, ARCH, for the target architecture
 AC_SUBST(ARCH,$llvm_cv_target_arch)
 
 dnl Check for the endianness of the target
-AC_C_BIGENDIAN(AC_SUBST([ENDIAN],[big]),AC_SUBST([ENDIAN],[little]))
+AC_C_BIGENDIAN([AC_SUBST([ENDIAN],[big]),
+                AC_DEFINE([MSB_FIRST], [1], [Define if this target is big endian])],
+               [AC_SUBST([ENDIAN],[little]),
+                AC_DEFINE([LSB_FIRST], [1], [Define if this target is little endian])])
 
 dnl Check for build platform executable suffix if we're crosscompiling
 if test "$cross_compiling" = yes; then
index 4b65605d5b05a75a1da6404bbe89ee65def83ca8..b1fa7c09f71f21176b6185ea40a313d03a9999e1 100755 (executable)
--- a/configure
+++ b/configure
@@ -828,7 +828,6 @@ NOLINKALL
 LLVM_ON_UNIX
 LLVM_ON_WIN32
 ARCH
-ENDIAN
 CC
 CFLAGS
 LDFLAGS
@@ -839,6 +838,7 @@ OBJEXT
 CPP
 GREP
 EGREP
+ENDIAN
 LLVM_CROSS_COMPILING
 BUILD_CC
 BUILD_EXEEXT
@@ -4183,9 +4183,19 @@ echo "${ECHO_T}$ac_cv_c_bigendian" >&6; }
 case $ac_cv_c_bigendian in
   yes)
     ENDIAN=big
+,
+
+cat >>confdefs.h <<\_ACEOF
+#define MSB_FIRST 1
+_ACEOF
  ;;
   no)
     ENDIAN=little
+,
+
+cat >>confdefs.h <<\_ACEOF
+#define LSB_FIRST 1
+_ACEOF
  ;;
   *)
     { { echo "$as_me:$LINENO: error: unknown endianness
@@ -8220,7 +8230,9 @@ if test "${enable_ltdl_install+set}" = set; then
 fi
 
 
- if test x"${enable_ltdl_install-no}" != xno; then
+
+
+if test x"${enable_ltdl_install-no}" != xno; then
   INSTALL_LTDL_TRUE=
   INSTALL_LTDL_FALSE='#'
 else
@@ -8228,7 +8240,9 @@ else
   INSTALL_LTDL_FALSE=
 fi
 
- if test x"${enable_ltdl_convenience-no}" != xno; then
+
+
+if test x"${enable_ltdl_convenience-no}" != xno; then
   CONVENIENCE_LTDL_TRUE=
   CONVENIENCE_LTDL_FALSE='#'
 else
@@ -9867,7 +9881,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 9870 "configure"
+#line 9884 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11802,7 +11816,7 @@ ia64-*-hpux*)
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 11805 "configure"' > conftest.$ac_ext
+  echo '#line 11819 "configure"' > conftest.$ac_ext
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -13442,11 +13456,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:13445: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:13459: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:13449: \$? = $ac_status" >&5
+   echo "$as_me:13463: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -13710,11 +13724,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:13713: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:13727: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:13717: \$? = $ac_status" >&5
+   echo "$as_me:13731: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -13814,11 +13828,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:13817: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:13831: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:13821: \$? = $ac_status" >&5
+   echo "$as_me:13835: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -16122,7 +16136,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 16125 "configure"
+#line 16139 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -16222,7 +16236,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 16225 "configure"
+#line 16239 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -18558,11 +18572,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:18561: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:18575: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:18565: \$? = $ac_status" >&5
+   echo "$as_me:18579: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -18662,11 +18676,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:18665: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:18679: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:18669: \$? = $ac_status" >&5
+   echo "$as_me:18683: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -20232,11 +20246,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:20235: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:20249: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:20239: \$? = $ac_status" >&5
+   echo "$as_me:20253: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -20336,11 +20350,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:20339: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:20353: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:20343: \$? = $ac_status" >&5
+   echo "$as_me:20357: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -22539,11 +22553,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:22542: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:22556: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:22546: \$? = $ac_status" >&5
+   echo "$as_me:22560: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -22807,11 +22821,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:22810: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:22824: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:22814: \$? = $ac_status" >&5
+   echo "$as_me:22828: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -22911,11 +22925,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:22914: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:22928: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:22918: \$? = $ac_status" >&5
+   echo "$as_me:22932: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -32755,7 +32769,6 @@ NOLINKALL!$NOLINKALL$ac_delim
 LLVM_ON_UNIX!$LLVM_ON_UNIX$ac_delim
 LLVM_ON_WIN32!$LLVM_ON_WIN32$ac_delim
 ARCH!$ARCH$ac_delim
-ENDIAN!$ENDIAN$ac_delim
 CC!$CC$ac_delim
 CFLAGS!$CFLAGS$ac_delim
 LDFLAGS!$LDFLAGS$ac_delim
@@ -32766,6 +32779,7 @@ OBJEXT!$OBJEXT$ac_delim
 CPP!$CPP$ac_delim
 GREP!$GREP$ac_delim
 EGREP!$EGREP$ac_delim
+ENDIAN!$ENDIAN$ac_delim
 LLVM_CROSS_COMPILING!$LLVM_CROSS_COMPILING$ac_delim
 BUILD_CC!$BUILD_CC$ac_delim
 BUILD_EXEEXT!$BUILD_EXEEXT$ac_delim
index 32e154a695f68d5a695a662eba68020c921e1131..64858f26b94c3a2de8ba49bd01e2033d4afbd384 100644 (file)
 /* Installation prefix directory */
 #undef LLVM_PREFIX
 
+/* Define if this target is little endian */
+#undef LSB_FIRST
+
 /* Define if the OS needs help to load dependent libraries for dlopen(). */
 #undef LTDL_DLOPEN_DEPLIBS
 
 /* Define to the system default library search path. */
 #undef LTDL_SYSSEARCHPATH
 
+/* Define if this target is big endian */
+#undef MSB_FIRST
+
 /* Define if /dev/zero should be used when mapping RWX memory, or undefine if
    its not necessary */
 #undef NEED_DEV_ZERO_FOR_MMAP
index 3136a38ac0fade7390b5cd56612901901976a1b9..fd52ef380abfd1696298df347c0a24189c80e17e 100644 (file)
@@ -23,6 +23,7 @@
 #include "llvm/Pass.h"
 #include "llvm/Support/DataTypes.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/Config/config.h"
 #include <string>
 
 namespace llvm {
@@ -142,6 +143,16 @@ public:
   bool          isLittleEndian()       const { return     LittleEndian; }
   bool          isBigEndian()          const { return    !LittleEndian; }
 
+  /// Host endianness...
+  bool hostIsLittleEndian() const {
+#ifdef LSB_FIRST
+    return true;
+#else
+    return false;
+#endif
+  }
+  bool hostIsBigEndian() const { return !hostIsLittleEndian(); }
+
   /// getStringRepresentation - Return the string representation of the
   /// TargetData.  This representation is in the same format accepted by the
   /// string constructor above.
index 02b94cc1fdbb0cf305bfffe87a3e5ce3920c06cc..2c7a7dd14432f41e3a4fe5a185ebeeb556dca519 100644 (file)
@@ -633,20 +633,27 @@ void ExecutionEngine::StoreValueToMemory(const GenericValue &Val, GenericValue *
   switch (Ty->getTypeID()) {
   case Type::IntegerTyID: {
     unsigned BitWidth = cast<IntegerType>(Ty)->getBitWidth();
-    GenericValue TmpVal = Val;
-    if (BitWidth <= 8)
-      *((uint8_t*)Ptr) = uint8_t(Val.IntVal.getZExtValue());
-    else if (BitWidth <= 16) {
-      *((uint16_t*)Ptr) = uint16_t(Val.IntVal.getZExtValue());
-    } else if (BitWidth <= 32) {
-      *((uint32_t*)Ptr) = uint32_t(Val.IntVal.getZExtValue());
-    } else if (BitWidth <= 64) {
-      *((uint64_t*)Ptr) = uint64_t(Val.IntVal.getZExtValue());
-    } else {
-      uint64_t *Dest = (uint64_t*)Ptr;
-      const uint64_t *Src = Val.IntVal.getRawData();
-      for (uint32_t i = 0; i < Val.IntVal.getNumWords(); ++i)
-        Dest[i] = Src[i];
+    unsigned StoreBytes = (BitWidth + 7)/8;
+    uint8_t *Src = (uint8_t *)Val.IntVal.getRawData();
+    uint8_t *Dst = (uint8_t *)Ptr;
+
+    if (getTargetData()->hostIsLittleEndian())
+      // Little-endian host - the source is ordered from LSB to MSB.
+      // Order the destination from LSB to MSB: Do a straight copy.
+      memcpy(Dst, Src, StoreBytes);
+    else {
+      // Big-endian host - the source is an array of 64 bit words ordered from
+      // LSW to MSW.  Each word is ordered from MSB to LSB.
+      // Order the destination from MSB to LSB: Reverse the word order, but not
+      // the bytes in a word.
+      while (StoreBytes > sizeof(uint64_t)) {
+        StoreBytes -= sizeof(uint64_t);
+        // May not be aligned so use memcpy.
+        memcpy(Dst + StoreBytes, Src, sizeof(uint64_t));
+        Src += sizeof(uint64_t);
+      }
+
+      memcpy(Dst, Src + sizeof(uint64_t) - StoreBytes, StoreBytes);
     }
     break;
   }
@@ -683,16 +690,32 @@ void ExecutionEngine::LoadValueFromMemory(GenericValue &Result,
   switch (Ty->getTypeID()) {
   case Type::IntegerTyID: {
     unsigned BitWidth = cast<IntegerType>(Ty)->getBitWidth();
-    if (BitWidth <= 8)
-      Result.IntVal = APInt(BitWidth, *((uint8_t*)Ptr));
-    else if (BitWidth <= 16) {
-      Result.IntVal = APInt(BitWidth, *((uint16_t*)Ptr));
-    } else if (BitWidth <= 32) {
-      Result.IntVal = APInt(BitWidth, *((uint32_t*)Ptr));
-    } else if (BitWidth <= 64) {
-      Result.IntVal = APInt(BitWidth, *((uint64_t*)Ptr));
-    } else
-      Result.IntVal = APInt(BitWidth, (BitWidth+63)/64, (uint64_t*)Ptr);
+    unsigned LoadBytes = (BitWidth + 7)/8;
+
+    // An APInt with all words initially zero.
+    Result.IntVal = APInt(BitWidth, 0);
+
+    uint8_t *Src = (uint8_t *)Ptr;
+    uint8_t *Dst = (uint8_t *)Result.IntVal.getRawData();
+
+    if (getTargetData()->hostIsLittleEndian())
+      // Little-endian host - the destination must be ordered from LSB to MSB.
+      // The source is ordered from LSB to MSB: Do a straight copy.
+      memcpy(Dst, Src, LoadBytes);
+    else {
+      // Big-endian - the destination is an array of 64 bit words ordered from
+      // LSW to MSW.  Each word must be ordered from MSB to LSB.  The source is
+      // ordered from MSB to LSB: Reverse the word order, but not the bytes in
+      // a word.
+      while (LoadBytes > sizeof(uint64_t)) {
+        LoadBytes -= sizeof(uint64_t);
+        // May not be aligned so use memcpy.
+        memcpy(Dst, Src + LoadBytes, sizeof(uint64_t));
+        Dst += sizeof(uint64_t);
+      }
+
+      memcpy(Dst + sizeof(uint64_t) - LoadBytes, Src, LoadBytes);
+    }
     break;
   }
   case Type::FloatTyID:
diff --git a/test/ExecutionEngine/2007-12-10-APIntLoadStore.ll b/test/ExecutionEngine/2007-12-10-APIntLoadStore.ll
new file mode 100644 (file)
index 0000000..7a337f9
--- /dev/null
@@ -0,0 +1,19 @@
+; RUN: llvm-as < %s -o - | lli -force-interpreter
+; PR1836
+
+define i32 @main() {
+entry:
+    %retval = alloca i32        ; <i32*> [#uses=2]
+    %tmp = alloca i32       ; <i32*> [#uses=2]
+    %x = alloca i75, align 16       ; <i75*> [#uses=1]
+    %"alloca point" = bitcast i32 0 to i32      ; <i32> [#uses=0]
+    store i75 999, i75* %x, align 16
+    store i32 0, i32* %tmp, align 4
+    %tmp1 = load i32* %tmp, align 4     ; <i32> [#uses=1]
+    store i32 %tmp1, i32* %retval, align 4
+    br label %return
+
+return:     ; preds = %entry
+    %retval2 = load i32* %retval        ; <i32> [#uses=1]
+    ret i32 %retval2
+}