]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Merge, from CGTUNE branch:
authorJulian Seward <jseward@acm.org>
Sat, 25 Aug 2007 21:11:33 +0000 (21:11 +0000)
committerJulian Seward <jseward@acm.org>
Sat, 25 Aug 2007 21:11:33 +0000 (21:11 +0000)
r1765:
During register allocation, keep track of which (real) registers have
the same value as their associated spill slot.  Then, if a register
needs to be freed up for some reason, and that register has the same
value as its spill slot, there is no need to produce a spill store.
This substantially reduces the number of spill store instructions
created.  Overall gives a 1.9% generated code size reduction for
perf/bz2 running on x86.

r1766:
Followup to r1765: fix some comments, and rearrange fields in struct
RRegState so as to fit it into 16 bytes.

git-svn-id: svn://svn.valgrind.org/vex/trunk@1778

VEX/priv/host-generic/reg_alloc2.c

index 638570fe4e6196f8acee851d061df0f613f6e545..6a58c3b04c8644f1bc854c64364fe8be3a8bcc42 100644 (file)
@@ -56,9 +56,6 @@
 
 /* TODO 27 Oct 04:
 
-   (Critical): Need a way to statically establish the vreg classes,
-   else we can't allocate spill slots properly.
-
    Better consistency checking from what isMove tells us.
 
    We can possibly do V-V coalescing even when the src is spilled,
 
    Note that state[].hreg is the same as the available real regs.
 
-   Check whether rreg preferencing has any beneficial effect.
-
-   Remove preferencing fields in VRegInfo, if not used.
-
    Generally rationalise data structures.  */
 
 
@@ -109,23 +102,30 @@ typedef
    updated as the allocator processes instructions. */
 typedef
    struct {
-      /* FIELDS WHICH DO NOT CHANGE */
+      /* ------ FIELDS WHICH DO NOT CHANGE ------ */
       /* Which rreg is this for? */
       HReg rreg;
       /* Is this involved in any HLRs?  (only an optimisation hint) */
       Bool has_hlrs;
-      /* FIELDS WHICH DO CHANGE */
+      /* ------ FIELDS WHICH DO CHANGE ------ */
+      /* 6 May 07: rearranged fields below so the whole struct fits
+         into 16 bytes on both x86 and amd64. */
+      /* Used when .disp == Bound and we are looking for vregs to
+         spill. */
+      Bool is_spill_cand;
+      /* Optimisation: used when .disp == Bound.  Indicates when the
+         rreg has the same value as the spill slot for the associated
+         vreg.  Is safely left at False, and becomes True after a
+         spill store or reload for this rreg. */
+      Bool eq_spill_slot;
       /* What's it's current disposition? */
       enum { Free,     /* available for use */
              Unavail,  /* in a real-reg live range */
              Bound     /* in use (holding value of some vreg) */
            }
            disp;
-      /* If RRegBound, what vreg is it bound to? */
+      /* If .disp == Bound, what vreg is it bound to? */
       HReg vreg;
-      /* Used when .disp == Bound and we are looking for vregs to
-         spill. */
-      Bool is_spill_cand;
    }
    RRegState;
 
@@ -339,6 +339,8 @@ HInstrArray* doRegisterAllocation (
 {
 #  define N_SPILL64S  (LibVEX_N_SPILL_BYTES / 8)
 
+   const Bool eq_spill_opt = True;
+
    /* Iterators and temporaries. */
    Int       ii, j, k, m, spillee, k_suboptimal;
    HReg      rreg, vreg, vregS, vregD;
@@ -462,6 +464,7 @@ HInstrArray* doRegisterAllocation (
       rreg_state[j].disp          = Free;
       rreg_state[j].vreg          = INVALID_HREG;
       rreg_state[j].is_spill_cand = False;
+      rreg_state[j].eq_spill_slot = False;
    }
 
    for (j = 0; j < n_vregs; j++)
@@ -783,7 +786,7 @@ HInstrArray* doRegisterAllocation (
       two spill slots.
 
       Do a rank-based allocation of vregs to spill slot numbers.  We
-      put as few values as possible in spill slows, but nevertheless
+      put as few values as possible in spill slots, but nevertheless
       need to have a spill slot available for all vregs, just in case.
    */
    /* max_ss_no = -1; */
@@ -956,8 +959,10 @@ HInstrArray* doRegisterAllocation (
          /* Sanity check 3: all vreg-rreg bindings must bind registers
             of the same class. */
          for (j = 0; j < n_rregs; j++) {
-            if (rreg_state[j].disp != Bound)
+            if (rreg_state[j].disp != Bound) {
+               vassert(rreg_state[j].eq_spill_slot == False);
                continue;
+            }
             vassert(hregClass(rreg_state[j].rreg) 
                     == hregClass(rreg_state[j].vreg));
             vassert( hregIsVirtual(rreg_state[j].vreg));
@@ -1033,6 +1038,10 @@ HInstrArray* doRegisterAllocation (
          vreg_state[hregNumber(vregD)] = toShort(m);
          vreg_state[hregNumber(vregS)] = INVALID_RREG_NO;
 
+         /* This rreg has become associated with a different vreg and
+            hence with a different spill slot.  Play safe. */
+         rreg_state[m].eq_spill_slot = False;
+
          /* Move on to the next insn.  We skip the post-insn stuff for
             fixed registers, since this move should not interact with
             them in any way. */
@@ -1052,6 +1061,7 @@ HInstrArray* doRegisterAllocation (
          vassert(IS_VALID_VREGNO(vreg));
          if (vreg_lrs[vreg].dead_before <= ii) {
             rreg_state[j].disp = Free;
+            rreg_state[j].eq_spill_slot = False;
             m = hregNumber(rreg_state[j].vreg);
             vassert(IS_VALID_VREGNO(m));
             vreg_state[m] = INVALID_RREG_NO;
@@ -1115,13 +1125,17 @@ HInstrArray* doRegisterAllocation (
             vreg_state[m] = INVALID_RREG_NO;
             if (vreg_lrs[m].dead_before > ii) {
                vassert(vreg_lrs[m].reg_class != HRcINVALID);
-               EMIT_INSTR( (*genSpill)( rreg_state[k].rreg,
-                                        vreg_lrs[m].spill_offset,
-                                        mode64 ) );
+               if ((!eq_spill_opt) || !rreg_state[k].eq_spill_slot) {
+                  EMIT_INSTR( (*genSpill)( rreg_state[k].rreg,
+                                           vreg_lrs[m].spill_offset,
+                                           mode64 ) );
+               }
+               rreg_state[k].eq_spill_slot = True;
             }
          }
          rreg_state[k].disp = Unavail;
          rreg_state[k].vreg = INVALID_HREG;
+         rreg_state[k].eq_spill_slot = False;
 
          /* check for further rregs entering HLRs at this point */
          rreg_lrs_la_next++;
@@ -1170,6 +1184,10 @@ HInstrArray* doRegisterAllocation (
          if (IS_VALID_RREGNO(k)) {
             vassert(rreg_state[k].disp == Bound);
             addToHRegRemap(&remap, vreg, rreg_state[k].rreg);
+            /* If this rreg is written or modified, mark it as different
+               from any spill slot value. */
+            if (reg_usage.mode[j] != HRmRead)
+               rreg_state[k].eq_spill_slot = False;
             continue;
          } else {
             vassert(k == INVALID_RREG_NO);
@@ -1205,13 +1223,22 @@ HInstrArray* doRegisterAllocation (
             vassert(IS_VALID_VREGNO(m));
             vreg_state[m] = toShort(k);
             addToHRegRemap(&remap, vreg, rreg_state[k].rreg);
-            /* Generate a reload if needed. */
+            /* Generate a reload if needed.  This only creates needed
+               reloads because the live range builder for vregs will
+               guarantee that the first event for a vreg is a write.
+               Hence, if this reference is not a write, it cannot be
+               the first reference for this vreg, and so a reload is
+               indeed needed. */
             if (reg_usage.mode[j] != HRmWrite) {
                vassert(vreg_lrs[m].reg_class != HRcINVALID);
                EMIT_INSTR( (*genReload)( rreg_state[k].rreg,
                                          vreg_lrs[m].spill_offset,
                                          mode64 ) );
+               rreg_state[k].eq_spill_slot = True;
+            } else {
+               rreg_state[k].eq_spill_slot = False;
             }
+
             continue;
          }
 
@@ -1272,15 +1299,19 @@ HInstrArray* doRegisterAllocation (
             live vreg. */
          vassert(vreg_lrs[m].dead_before > ii);
          vassert(vreg_lrs[m].reg_class != HRcINVALID);
-         EMIT_INSTR( (*genSpill)( rreg_state[spillee].rreg,
-                                  vreg_lrs[m].spill_offset,
-                                  mode64 ) );
+         if ((!eq_spill_opt) || !rreg_state[spillee].eq_spill_slot) {
+            EMIT_INSTR( (*genSpill)( rreg_state[spillee].rreg,
+                                     vreg_lrs[m].spill_offset,
+                                     mode64 ) );
+         }
 
          /* Update the rreg_state to reflect the new assignment for this
             rreg. */
          rreg_state[spillee].vreg = vreg;
          vreg_state[m] = INVALID_RREG_NO;
 
+         rreg_state[spillee].eq_spill_slot = False; /* be safe */
+
          m = hregNumber(vreg);
          vassert(IS_VALID_VREGNO(m));
          vreg_state[m] = toShort(spillee);
@@ -1292,6 +1323,7 @@ HInstrArray* doRegisterAllocation (
             EMIT_INSTR( (*genReload)( rreg_state[spillee].rreg,
                                       vreg_lrs[m].spill_offset,
                                       mode64 ) );
+            rreg_state[spillee].eq_spill_slot = True;
          }
 
          /* So after much twisting and turning, we have vreg mapped to
@@ -1344,6 +1376,7 @@ HInstrArray* doRegisterAllocation (
          vassert(rreg_state[k].disp == Unavail);
          rreg_state[k].disp = Free;
          rreg_state[k].vreg = INVALID_HREG;
+         rreg_state[k].eq_spill_slot = False;
 
          /* check for further rregs leaving HLRs at this point */
          rreg_lrs_db_next++;