Index: priv/main/vex_main.c =================================================================== --- priv/main/vex_main.c (revision 1849) +++ priv/main/vex_main.c (working copy) @@ -206,6 +206,7 @@ Bool host_is_bigendian = False; IRSB* irsb; HInstrArray* vcode; + HInstrArray* pcode; HInstrArray* rcode; Int i, j, k, out_used, guest_sizeB; Int offB_TISTART, offB_TILEN; @@ -584,8 +585,31 @@ vex_printf("\n"); } + if (vex_traceflags & VEX_TRACE_VCODE) + vex_printf("\n------------------------" + " Peephole optimizations " + "------------------------\n"); + + pcode = peephole_optimizations ( vcode, isMove, getRegUsage, + mapRegs, ppInstr, ppReg, + mode64 ); + + vexAllocSanityCheck(); + + if (vex_traceflags & VEX_TRACE_VCODE) + vex_printf("\n"); + + if (vex_traceflags & VEX_TRACE_VCODE) { + for (i = 0; i < pcode->arr_used; i++) { + vex_printf("%3d ", i); + ppInstr(pcode->arr[i], mode64); + vex_printf("\n"); + } + vex_printf("\n"); + } + /* Register allocate. */ - rcode = doRegisterAllocation ( vcode, available_real_regs, + rcode = doRegisterAllocation ( pcode, available_real_regs, n_available_real_regs, isMove, getRegUsage, mapRegs, genSpill, genReload, directReload, Index: priv/host-generic/peephole.c =================================================================== --- priv/host-generic/peephole.c (revision 0) +++ priv/host-generic/peephole.c (revision 0) @@ -0,0 +1,233 @@ +/*---------------------------------------------------------------*/ +/*--- ---*/ +/*--- This file (host-generic/peephole.c) is ---*/ +/*--- Copyright (C) OpenWorks LLP. All rights reserved. ---*/ +/*--- ---*/ +/*---------------------------------------------------------------*/ + +/* + This file is part of LibVEX, a library for dynamic binary + instrumentation and translation. + + Copyright (C) 2004-2008 OpenWorks LLP. All rights reserved. + + This library is made available under a dual licensing scheme. + + If you link LibVEX against other code all of which is itself + licensed under the GNU General Public License, version 2 dated June + 1991 ("GPL v2"), then you may use LibVEX under the terms of the GPL + v2, as appearing in the file LICENSE.GPL. If the file LICENSE.GPL + is missing, you can obtain a copy of the GPL v2 from the Free + Software Foundation Inc., 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301, USA. + + For any other uses of LibVEX, you must first obtain a commercial + license from OpenWorks LLP. Please contact info@open-works.co.uk + for information about commercial licensing. + + This software is provided by OpenWorks LLP "as is" and any express + or implied warranties, including, but not limited to, the implied + warranties of merchantability and fitness for a particular purpose + are disclaimed. In no event shall OpenWorks LLP be liable for any + direct, indirect, incidental, special, exemplary, or consequential + damages (including, but not limited to, procurement of substitute + goods or services; loss of use, data, or profits; or business + interruption) however caused and on any theory of liability, + whether in contract, strict liability, or tort (including + negligence or otherwise) arising in any way out of the use of this + software, even if advised of the possibility of such damage. + + Neither the names of the U.S. Department of Energy nor the + University of California nor the names of its contributors may be + used to endorse or promote products derived from this software + without prior written permission. +*/ + +#include "libvex_basictypes.h" +#include "libvex.h" + +#include "main/vex_util.h" +#include "host-generic/h_generic_regs.h" + + +#define DEBUG_PEEPHOLE 0 + + +/* Records information on virtual register live ranges. Computed once + and remains unchanged after that. */ +typedef + struct { + Short last_used; + HReg replace_with; + } + VRegLR; + + +/* Perform PeepHole Optimizations. May return a new HInstrArray, but + individual HInstrs are replaced in-place. + + Optimizations that are performed: + * redudant 'MOV vreg, vreg' removal + * dead stores to vregs removal +*/ +HInstrArray* peephole_optimizations( + /* Incoming virtual-registerised code. */ + HInstrArray* instrs_in, + + /* Return True iff the given insn is a reg-reg move, in which + case also return the src and dst regs. */ + Bool (*isMove) ( HInstr*, HReg*, HReg* ), + + /* Get info about register usage in this insn. */ + void (*getRegUsage) (HRegUsage*, HInstr*, Bool), + + /* Apply a reg-reg mapping to an insn. */ + void (*mapRegs) (HRegRemap*, HInstr*, Bool), + + /* For debug printing only. */ + void (*ppInstr) ( HInstr*, Bool ), + void (*ppReg) ( HReg ), + + /* 32/64bit mode */ + Bool mode64 +) +{ + Int i, j, k, m; + Int n_vregs; + VRegLR *vreg_lrs; /* [0 .. n_vregs-1] */ + HInstrArray *instrs_out; + + n_vregs = instrs_in->n_vregs; + + if (n_vregs == 0) { + return instrs_in; /* really nothing to do */ + } + + instrs_out = newHInstrArray(); + instrs_out->n_vregs = n_vregs; + + vreg_lrs = LibVEX_Alloc(sizeof(VRegLR) * n_vregs); + + for (j = 0; j < n_vregs; j++) { + vreg_lrs[j].replace_with = INVALID_HREG; + } + + + /* record when each virtual register was last used */ + for (i = 0; i < instrs_in->arr_used; i++) { + HRegUsage reg_usage; + getRegUsage(®_usage, instrs_in->arr[i], mode64); + + for (j = 0; j < reg_usage.n_used; j++) { + HReg vreg = reg_usage.hreg[j]; + + if (!hregIsVirtual(vreg)) + continue; + + k = hregNumber(vreg); + vreg_lrs[k].last_used = toShort(i); + } + } + + + /* now remove redudant MOVs */ + for (i = 0; i < instrs_in->arr_used; i++) { + HReg reg1, reg2; + HInstr *instr = instrs_in->arr[i]; + Bool ismove = isMove(instr, ®1, ®2); + +#if DEBUG_PEEPHOLE + vex_printf("\n---\n%d ", i); + ppInstr(instr, mode64); + vex_printf("\n"); +#endif + + if (ismove == True) { +/* -- does not happen? + if (reg1 == reg2) { +#if DEBUG_PEEPHOLE + vex_printf("move to itself\n"); +#endif + continue; + } +*/ + + k = hregNumber(reg1); + m = hregNumber(reg2); + + /* assignment to %vrX and %vrX isn't used after this instruction */ + if (hregIsVirtual(reg2) && vreg_lrs[m].last_used == i) { +#if DEBUG_PEEPHOLE + vex_printf("dead assignment to: "); + ppReg(reg2); + vex_printf("\n"); +#endif + continue; + } + + /* if the source isn't used anymore, just kill this move */ + if (hregIsVirtual(reg1) && hregIsVirtual(reg2) && vreg_lrs[k].last_used == i) { + if (vreg_lrs[k].replace_with == INVALID_HREG) { + vreg_lrs[m].replace_with = reg1; + } else { + vreg_lrs[m].replace_with = vreg_lrs[k].replace_with; + } + +#if DEBUG_PEEPHOLE + vex_printf("map "); + ppReg(reg2); + vex_printf(" into "); + ppReg(vreg_lrs[m].replace_with); + vex_printf("\n"); +#endif + continue; + } + } + + { + HRegRemap remap; + HRegUsage reg_usage; + Bool map = False; + + initHRegRemap(&remap); + getRegUsage(®_usage, instr, mode64); + + /* replace old registers with new ones */ + for (j = 0; j < reg_usage.n_used; j++) { + HReg reg_orig, reg_new; + + reg_orig = reg_usage.hreg[j]; + + if (!hregIsVirtual(reg_orig)) { + continue; + } + + reg_new = vreg_lrs[hregNumber(reg_orig)].replace_with; + + if (reg_new != INVALID_HREG) { +#if DEBUG_PEEPHOLE + vex_printf("replace "); + ppReg(reg_orig); + vex_printf(" with "); + ppReg(reg_new); + vex_printf("\n"); +#endif + map = True; + } else { + reg_new = reg_orig; + } + + vassert(hregIsVirtual(reg_new)); + addToHRegRemap(&remap, reg_orig, reg_new); + } + + if (map == True) { + mapRegs(&remap, instr, mode64); + } + } + + addHInstr(instrs_out, instr); + } + + return instrs_out; +} Index: priv/host-generic/h_generic_regs.c =================================================================== --- priv/host-generic/h_generic_regs.c (revision 1849) +++ priv/host-generic/h_generic_regs.c (working copy) @@ -174,8 +174,8 @@ vpanic("addToHRegMap: duplicate entry"); if (!hregIsVirtual(orig)) vpanic("addToHRegMap: orig is not a vreg"); - if (hregIsVirtual(replacement)) - vpanic("addToHRegMap: replacement is not a vreg"); + /* if (hregIsVirtual(replacement)) + vpanic("addToHRegMap: replacement is a vreg"); */ vassert(map->n_used+1 < N_HREG_REMAP); map->orig[map->n_used] = orig; Index: priv/host-generic/h_generic_regs.h =================================================================== --- priv/host-generic/h_generic_regs.h (revision 1849) +++ priv/host-generic/h_generic_regs.h (working copy) @@ -281,6 +281,30 @@ ); +extern +HInstrArray* peephole_optimizations( + /* Incoming virtual-registerised code. */ + HInstrArray* instrs_in, + + /* Return True iff the given insn is a reg-reg move, in which + case also return the src and dst regs. */ + Bool (*isMove) ( HInstr*, HReg*, HReg* ), + + /* Get info about register usage in this insn. */ + void (*getRegUsage) (HRegUsage*, HInstr*, Bool), + + /* Apply a reg-reg mapping to an insn. */ + void (*mapRegs) (HRegRemap*, HInstr*, Bool), + + /* For debug printing only. */ + void (*ppInstr) ( HInstr*, Bool ), + void (*ppReg) ( HReg ), + + /* 32/64bit mode */ + Bool mode64 +); + + #endif /* ndef __H_GENERIC_REGS_H */ /*---------------------------------------------------------------*/ Index: Makefile =================================================================== --- Makefile (revision 1849) +++ Makefile (working copy) @@ -45,6 +45,7 @@ priv/host-generic/h_generic_regs.o \ priv/host-generic/h_generic_simd64.o \ priv/host-generic/reg_alloc2.o \ + priv/host-generic/peephole.o \ priv/guest-generic/g_generic_x87.o \ priv/guest-generic/bb_to_IR.o \ priv/guest-x86/ghelpers.o \ @@ -259,6 +260,10 @@ $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-generic/reg_alloc2.o \ -c priv/host-generic/reg_alloc2.c +priv/host-generic/peephole.o: $(ALL_HEADERS) priv/host-generic/peephole.c + $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-generic/peephole.o \ + -c priv/host-generic/peephole.c + priv/guest-x86/toIR.o: $(ALL_HEADERS) priv/guest-x86/toIR.c $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/guest-x86/toIR.o \ -c priv/guest-x86/toIR.c