]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
chainXDirect_ARM: generate direct jumps when possible.
authorJulian Seward <jseward@acm.org>
Sat, 21 Apr 2012 10:47:41 +0000 (10:47 +0000)
committerJulian Seward <jseward@acm.org>
Sat, 21 Apr 2012 10:47:41 +0000 (10:47 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@2301

VEX/priv/host_arm_defs.c

index 755699ebe5a7c4a0e860f9248ef0c272c6b4e463..645027fda5a794ec11608812470e153940fe8814 100644 (file)
@@ -4516,18 +4516,62 @@ VexInvalRange chainXDirect_ARM ( void* place_to_chain,
    vassert(is_imm32_to_iregNo_EXACTLY2(
               p, /*r*/12, (UInt)Ptr_to_ULong(disp_cp_chain_me_EXPECTED)));
    vassert(p[2] == 0xE12FFF3C);
-   /* And what we want to change it to is:
-        movw r12, lo16(place_to_jump_to)
-        movt r12, hi16(place_to_jump_to)
-        bx   r12
-      viz
-        <8 bytes generated by imm32_to_iregNo_EXACTLY2>
-        E1 2F FF 1C
-      The replacement has the same length as the original.
+   /* And what we want to change it to is either:
+        (general case)
+          movw r12, lo16(place_to_jump_to)
+          movt r12, hi16(place_to_jump_to)
+          bx   r12
+        viz
+          <8 bytes generated by imm32_to_iregNo_EXACTLY2>
+          E1 2F FF 1C
+      ---OR---
+        in the case where the displacement falls within 26 bits
+          b disp24; undef; undef
+        viz
+          EA <3 bytes == disp24>
+          FF 00 00 00
+          FF 00 00 00
+
+      In both cases the replacement has the same length as the original.
+      To remain sane & verifiable,
+      (1) limit the displacement for the short form to 
+          (say) +/- 30 million, so as to avoid wraparound
+          off-by-ones
+      (2) even if the short form is applicable, once every (say)
+          1024 times use the long form anyway, so as to maintain
+          verifiability
    */
-   (void)imm32_to_iregNo_EXACTLY2(
-            p, /*r*/12, (UInt)Ptr_to_ULong(place_to_jump_to));
-   p[2] = 0xE12FFF1C;
+
+   /* This is the delta we need to put into a B insn.  It's relative
+      to the start of the next-but-one insn, hence the -8.  */
+   Long delta   = (Long)((UChar*)place_to_jump_to - (UChar*)p) - (Long)8;
+   Bool shortOK = delta >= -30*1000*1000 && delta < 30*1000*1000;
+   vassert(0 == (delta & (Long)3));
+
+   static UInt shortCTR = 0; /* DO NOT MAKE NON-STATIC */
+   if (shortOK) {
+      shortCTR++; // thread safety bleh
+      if (0 == (shortCTR & 0x3FF)) {
+         shortOK = False;
+         if (0)
+            vex_printf("QQQ chainXDirect_ARM: shortCTR = %u, "
+                       "using long form\n", shortCTR);
+      }
+   }
+
+   /* And make the modifications. */
+   if (shortOK) {
+      Int simm24 = (Int)(delta >> 2);
+      vassert(simm24 == ((simm24 << 8) >> 8));
+      p[0] = 0xEA000000 | (simm24 & 0x00FFFFFF);
+      p[1] = 0xFF000000;
+      p[2] = 0xFF000000;
+   } else {
+      (void)imm32_to_iregNo_EXACTLY2(
+               p, /*r*/12, (UInt)Ptr_to_ULong(place_to_jump_to));
+      p[2] = 0xE12FFF1C;
+   }
+
    VexInvalRange vir = {(HWord)p, 12};
    return vir;
 }
@@ -4540,18 +4584,44 @@ VexInvalRange unchainXDirect_ARM ( void* place_to_unchain,
                                    void* disp_cp_chain_me )
 {
    /* What we're expecting to see is:
-        movw r12, lo16(place_to_jump_to_EXPECTED)
-        movt r12, lo16(place_to_jump_to_EXPECTED)
-        bx   r12
-      viz
-        <8 bytes generated by imm32_to_iregNo_EXACTLY2>
-        E1 2F FF 1C
+        (general case)
+          movw r12, lo16(place_to_jump_to_EXPECTED)
+          movt r12, lo16(place_to_jump_to_EXPECTED)
+          bx   r12
+        viz
+          <8 bytes generated by imm32_to_iregNo_EXACTLY2>
+          E1 2F FF 1C
+      ---OR---
+        in the case where the displacement falls within 26 bits
+          b disp24; undef; undef
+        viz
+          EA <3 bytes == disp24>
+          FF 00 00 00
+          FF 00 00 00
    */
    UInt* p = (UInt*)place_to_unchain;
    vassert(0 == (3 & (HWord)p));
-   vassert(is_imm32_to_iregNo_EXACTLY2(
-              p, /*r*/12, (UInt)Ptr_to_ULong(place_to_jump_to_EXPECTED)));
-   vassert(p[2] == 0xE12FFF1C);
+
+   Bool valid = False;
+   if (is_imm32_to_iregNo_EXACTLY2(
+          p, /*r*/12, (UInt)Ptr_to_ULong(place_to_jump_to_EXPECTED))
+       && p[2] == 0xE12FFF1C) {
+      valid = True; /* it's the long form */
+      if (0)
+         vex_printf("QQQ unchainXDirect_ARM: found long form\n");
+   } else
+   if ((p[0] >> 24) == 0xEA && p[1] == 0xFF000000 && p[2] == 0xFF000000) {
+      /* It's the short form.  Check the displacement is right. */
+      Int simm24 = p[0] & 0x00FFFFFF;
+      simm24 <<= 8; simm24 >>= 8;
+      if ((UChar*)p + (simm24 << 2) + 8 == (UChar*)place_to_jump_to_EXPECTED) {
+         valid = True;
+         if (0)
+            vex_printf("QQQ unchainXDirect_ARM: found short form\n");
+      }
+   }
+   vassert(valid);
+
    /* And what we want to change it to is:
         movw r12, lo16(disp_cp_chain_me)
         movt r12, hi16(disp_cp_chain_me)