Imported Upstream version 0.160
[platform/upstream/elfutils.git] / libdw / memory-access.h
index 5773e5c..f41f783 100644 (file)
@@ -1,5 +1,5 @@
 /* Unaligned memory access functionality.
-   Copyright (C) 2000-2010 Red Hat, Inc.
+   Copyright (C) 2000-2014 Red Hat, Inc.
    This file is part of elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2001.
 
 
 /* Number decoding macros.  See 7.6 Variable Length Data.  */
 
-#define get_uleb128_step(var, addr, nth, break)                                      \
-    __b = *(addr)++;                                                         \
-    var |= (uintmax_t) (__b & 0x7f) << (nth * 7);                            \
-    if (likely ((__b & 0x80) == 0))                                          \
-      break
-
-#define get_uleb128(var, addr)                                               \
-  do {                                                                       \
-    unsigned char __b;                                                       \
-    var = 0;                                                                 \
-    get_uleb128_step (var, addr, 0, break);                                  \
-    var = __libdw_get_uleb128 (var, 1, &(addr));                             \
-  } while (0)
+#define len_leb128(var) ((8 * sizeof (var) + 6) / 7)
 
-#define get_uleb128_rest_return(var, i, addrp)                               \
+#define get_uleb128_step(var, addr, nth)                                     \
   do {                                                                       \
-    for (; i < 10; ++i)                                                              \
-      {                                                                              \
-       get_uleb128_step (var, *addrp, i, return var);                        \
-      }                                                                              \
-    /* Other implementations set VALUE to UINT_MAX in this                   \
-       case.  So we better do this as well.  */                                      \
-    return UINT64_MAX;                                                       \
+    unsigned char __b = *(addr)++;                                           \
+    (var) |= (typeof (var)) (__b & 0x7f) << ((nth) * 7);                     \
+    if (likely ((__b & 0x80) == 0))                                          \
+      return (var);                                                          \
   } while (0)
 
-/* The signed case is similar, but we sign-extend the result.  */
+static inline uint64_t
+__libdw_get_uleb128 (const unsigned char **addrp)
+{
+  uint64_t acc = 0;
+  /* Unroll the first step to help the compiler optimize
+     for the common single-byte case.  */
+  get_uleb128_step (acc, *addrp, 0);
+  for (unsigned int i = 1; i < len_leb128 (acc); ++i)
+    get_uleb128_step (acc, *addrp, i);
+  /* Other implementations set VALUE to UINT_MAX in this
+     case.  So we better do this as well.  */
+  return UINT64_MAX;
+}
 
-#define get_sleb128_step(var, addr, nth, break)                                      \
-    __b = *(addr)++;                                                         \
-    _v |= (uint64_t) (__b & 0x7f) << (nth * 7);                                      \
-    if (likely ((__b & 0x80) == 0))                                          \
-      {                                                                              \
-       var = (_v << (64 - (nth * 7) - 7)) >> (64 - (nth * 7) - 7);           \
-        break;                                                               \
-      }                                                                              \
-    else do {} while (0)
+#define get_uleb128(var, addr) ((var) = __libdw_get_uleb128 (&(addr)))
 
-#define get_sleb128(var, addr)                                               \
-  do {                                                                       \
-    unsigned char __b;                                                       \
-    int64_t _v = 0;                                                          \
-    get_sleb128_step (var, addr, 0, break);                                  \
-    var = __libdw_get_sleb128 (_v, 1, &(addr));                                      \
-  } while (0)
+/* The signed case is similar, but we sign-extend the result.  */
 
-#define get_sleb128_rest_return(var, i, addrp)                               \
+#define get_sleb128_step(var, addr, nth)                                     \
   do {                                                                       \
-    for (; i < 9; ++i)                                                       \
+    unsigned char __b = *(addr)++;                                           \
+    if (likely ((__b & 0x80) == 0))                                          \
       {                                                                              \
-       get_sleb128_step (var, *addrp, i, return var);                        \
+       struct { signed int i:7; } __s = { .i = __b };                        \
+       (var) |= (typeof (var)) __s.i * ((typeof (var)) 1 << ((nth) * 7));    \
+       return (var);                                                         \
       }                                                                              \
-    __b = *(*addrp)++;                                                       \
-    if (likely ((__b & 0x80) == 0))                                          \
-      return var | ((uint64_t) __b << 63);                                   \
-    else                                                                     \
-      /* Other implementations set VALUE to INT_MAX in this                  \
-        case.  So we better do this as well.  */                             \
-      return INT64_MAX;                                                              \
+    (var) |= (typeof (var)) (__b & 0x7f) << ((nth) * 7);                     \
   } while (0)
 
-#ifdef IS_LIBDW
-extern uint64_t __libdw_get_uleb128 (uint64_t acc, unsigned int i,
-                                    const unsigned char **addrp)
-     internal_function attribute_hidden;
-extern int64_t __libdw_get_sleb128 (int64_t acc, unsigned int i,
-                                   const unsigned char **addrp)
-     internal_function attribute_hidden;
-#else
-static inline uint64_t
-__attribute__ ((unused))
-__libdw_get_uleb128 (uint64_t acc, unsigned int i, const unsigned char **addrp)
-{
-  unsigned char __b;
-  get_uleb128_rest_return (acc, i, addrp);
-}
 static inline int64_t
-__attribute__ ((unused))
-__libdw_get_sleb128 (int64_t acc, unsigned int i, const unsigned char **addrp)
+__libdw_get_sleb128 (const unsigned char **addrp)
 {
-  unsigned char __b;
-  int64_t _v = acc;
-  get_sleb128_rest_return (acc, i, addrp);
+  int64_t acc = 0;
+  /* Unrolling 0 like uleb128 didn't prove to benefit optimization.  */
+  for (unsigned int i = 0; i < len_leb128 (acc); ++i)
+    get_sleb128_step (acc, *addrp, i);
+  /* Other implementations set VALUE to INT_MAX in this
+     case.  So we better do this as well.  */
+  return INT64_MAX;
 }
-#endif
+
+#define get_sleb128(var, addr) ((var) = __libdw_get_sleb128 (&(addr)))
 
 
 /* We use simple memory access functions in case the hardware allows it.
@@ -147,6 +116,8 @@ __libdw_get_sleb128 (int64_t acc, unsigned int i, const unsigned char **addrp)
    ? (int32_t) bswap_32 (*((const int32_t *) (Addr)))                        \
    : *((const int32_t *) (Addr)))
 
+# define read_8ubyte_unaligned_noncvt(Addr) \
+   *((const uint64_t *) (Addr))
 # define read_8ubyte_unaligned(Dbg, Addr) \
   (unlikely ((Dbg)->other_byte_order)                                        \
    ? bswap_64 (*((const uint64_t *) (Addr)))                                 \
@@ -223,6 +194,12 @@ read_4sbyte_unaligned_1 (bool other_byte_order, const void *p)
 }
 
 static inline uint64_t
+read_8ubyte_unaligned_noncvt (const void *p)
+{
+  const union unaligned *up = p;
+  return up->u8;
+}
+static inline uint64_t
 read_8ubyte_unaligned_1 (bool other_byte_order, const void *p)
 {
   const union unaligned *up = p;