From: Julian Seward Date: Tue, 7 May 2002 23:38:30 +0000 (+0000) Subject: Generate better ucode for back-to-back sequences of register pushes and X-Git-Tag: svn/VALGRIND_1_0_3~237 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6a3788061fbd60f525be0636754075aeff1a7a4b;p=thirdparty%2Fvalgrind.git Generate better ucode for back-to-back sequences of register pushes and pops, as appear at function prologues/epilogues. Specifically, update %ESP just once for the whole sequence. This reduces by about 20% the number of calls to handle_esp_assignment (for kate in KDE 3.0, -O), which is a good thing since that is quite expensive. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@227 --- diff --git a/coregrind/vg_memory.c b/coregrind/vg_memory.c index 59d183b48a..a6a2c5d929 100644 --- a/coregrind/vg_memory.c +++ b/coregrind/vg_memory.c @@ -99,7 +99,7 @@ #ifdef VG_PROFILE_MEMORY -#define N_PROF_EVENTS 120 +#define N_PROF_EVENTS 150 static UInt event_ctr[N_PROF_EVENTS]; @@ -204,16 +204,23 @@ static void init_prof_mem ( void ) { } 101 handle_esp_assignment 102 handle_esp_assignment(-4) 103 handle_esp_assignment(+4) - 104 handle_esp_assignment(+16) - 105 handle_esp_assignment(-12) - 106 handle_esp_assignment(+8) - 107 handle_esp_assignment(-8) - - 110 vg_handle_esp_assignment_SLOWLY - 111 vg_handle_esp_assignment_SLOWLY(normal; move down) - 112 vg_handle_esp_assignment_SLOWLY(normal; move up) - 113 vg_handle_esp_assignment_SLOWLY(normal) - 114 vg_handle_esp_assignment_SLOWLY(>= HUGE_DELTA) + 104 handle_esp_assignment(-12) + 105 handle_esp_assignment(-8) + 106 handle_esp_assignment(+16) + 107 handle_esp_assignment(+12) + 108 handle_esp_assignment(0) + 109 handle_esp_assignment(+8) + 110 handle_esp_assignment(-16) + 111 handle_esp_assignment(+20) + 112 handle_esp_assignment(-20) + 113 handle_esp_assignment(+24) + 114 handle_esp_assignment(-24) + + 120 vg_handle_esp_assignment_SLOWLY + 121 vg_handle_esp_assignment_SLOWLY(normal; move down) + 122 vg_handle_esp_assignment_SLOWLY(normal; move up) + 123 vg_handle_esp_assignment_SLOWLY(normal) + 124 vg_handle_esp_assignment_SLOWLY(>= HUGE_DELTA) */ /*------------------------------------------------------------*/ @@ -712,7 +719,6 @@ static __inline__ UInt shiftRight16 ( UInt x ) Under all other circumstances, it defers to the relevant _SLOWLY function, which can handle all situations. */ - UInt VG_(helperc_LOADV4) ( Addr a ) { # ifdef VG_DEBUG_MEMORY @@ -1384,9 +1390,23 @@ void VGM_(handle_esp_assignment) ( Addr new_espA ) return; } - if (delta == 16) { - /* Also surprisingly common. */ + if (delta == -12) { PROF_EVENT(104); + make_aligned_word_WRITABLE(new_esp); + make_aligned_word_WRITABLE(new_esp+4); + make_aligned_word_WRITABLE(new_esp+8); + return; + } + + if (delta == -8) { + PROF_EVENT(105); + make_aligned_word_WRITABLE(new_esp); + make_aligned_word_WRITABLE(new_esp+4); + return; + } + + if (delta == 16) { + PROF_EVENT(106); make_aligned_word_NOACCESS(old_esp); make_aligned_word_NOACCESS(old_esp+4); make_aligned_word_NOACCESS(old_esp+8); @@ -1394,27 +1414,77 @@ void VGM_(handle_esp_assignment) ( Addr new_espA ) return; } - if (delta == -12) { - PROF_EVENT(105); + if (delta == 12) { + PROF_EVENT(107); + make_aligned_word_NOACCESS(old_esp); + make_aligned_word_NOACCESS(old_esp+4); + make_aligned_word_NOACCESS(old_esp+8); + return; + } + + if (delta == 0) { + PROF_EVENT(108); + return; + } + + if (delta == 8) { + PROF_EVENT(109); + make_aligned_word_NOACCESS(old_esp); + make_aligned_word_NOACCESS(old_esp+4); + return; + } + + if (delta == -16) { + PROF_EVENT(110); make_aligned_word_WRITABLE(new_esp); make_aligned_word_WRITABLE(new_esp+4); make_aligned_word_WRITABLE(new_esp+8); + make_aligned_word_WRITABLE(new_esp+12); return; } - if (delta == 8) { - PROF_EVENT(106); + if (delta == 20) { + PROF_EVENT(111); make_aligned_word_NOACCESS(old_esp); make_aligned_word_NOACCESS(old_esp+4); + make_aligned_word_NOACCESS(old_esp+8); + make_aligned_word_NOACCESS(old_esp+12); + make_aligned_word_NOACCESS(old_esp+16); return; } - if (delta == -8) { - PROF_EVENT(107); + if (delta == -20) { + PROF_EVENT(112); make_aligned_word_WRITABLE(new_esp); make_aligned_word_WRITABLE(new_esp+4); + make_aligned_word_WRITABLE(new_esp+8); + make_aligned_word_WRITABLE(new_esp+12); + make_aligned_word_WRITABLE(new_esp+16); return; } + + if (delta == 24) { + PROF_EVENT(113); + make_aligned_word_NOACCESS(old_esp); + make_aligned_word_NOACCESS(old_esp+4); + make_aligned_word_NOACCESS(old_esp+8); + make_aligned_word_NOACCESS(old_esp+12); + make_aligned_word_NOACCESS(old_esp+16); + make_aligned_word_NOACCESS(old_esp+20); + return; + } + + if (delta == -24) { + PROF_EVENT(114); + make_aligned_word_WRITABLE(new_esp); + make_aligned_word_WRITABLE(new_esp+4); + make_aligned_word_WRITABLE(new_esp+8); + make_aligned_word_WRITABLE(new_esp+12); + make_aligned_word_WRITABLE(new_esp+16); + make_aligned_word_WRITABLE(new_esp+20); + return; + } + } # endif @@ -1431,23 +1501,23 @@ static void vg_handle_esp_assignment_SLOWLY ( Addr new_espA ) UInt old_esp = VG_(baseBlock)[VGOFF_(m_esp)]; UInt new_esp = (UInt)new_espA; Int delta = ((Int)new_esp) - ((Int)old_esp); - - PROF_EVENT(110); + // VG_(printf)("%d ", delta); + PROF_EVENT(120); if (-(VG_HUGE_DELTA) < delta && delta < VG_HUGE_DELTA) { /* "Ordinary" stack change. */ if (new_esp < old_esp) { /* Moving down; the stack is growing. */ - PROF_EVENT(111); + PROF_EVENT(121); VGM_(make_writable) ( new_esp, old_esp - new_esp ); return; } if (new_esp > old_esp) { /* Moving up; the stack is shrinking. */ - PROF_EVENT(112); + PROF_EVENT(122); VGM_(make_noaccess) ( old_esp, new_esp - old_esp ); return; } - PROF_EVENT(113); + PROF_EVENT(123); return; /* when old_esp == new_esp */ } @@ -1470,7 +1540,7 @@ static void vg_handle_esp_assignment_SLOWLY ( Addr new_espA ) Addr valid_up_to = get_page_base(new_esp) + VKI_BYTES_PER_PAGE + 0 * VKI_BYTES_PER_PAGE; ThreadState* tst = VG_(get_current_thread_state)(); - PROF_EVENT(114); + PROF_EVENT(124); if (VG_(clo_verbosity) > 1) VG_(message)(Vg_UserMsg, "Warning: client switching stacks? " "%%esp: %p --> %p", diff --git a/coregrind/vg_to_ucode.c b/coregrind/vg_to_ucode.c index 4be838c193..607926ed65 100644 --- a/coregrind/vg_to_ucode.c +++ b/coregrind/vg_to_ucode.c @@ -3704,10 +3704,42 @@ static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd ) case 0x59: /* POP eCX */ case 0x5A: /* POP eDX */ case 0x5B: /* POP eBX */ - case 0x5C: /* POP eSP */ case 0x5D: /* POP eBP */ case 0x5E: /* POP eSI */ case 0x5F: /* POP eDI */ + { Int n_pops; + Addr eipS, eipE; + UChar ch; + if (sz != 4) goto normal_pop_case; + /* eip points at first pop insn + 1. Make eipS and eipE + bracket the sequence. */ + eipE = eipS = eip - 1; + while (True) { + ch = getUChar(eipE+1); + if (ch < 0x58 || ch > 0x5F || ch == 0x5C) break; + eipE++; + } + n_pops = eipE - eipS + 1; + if (0 && n_pops > 1) VG_(printf)("%d pops\n", n_pops); + t1 = newTemp(cb); t3 = newTemp(cb); + uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1); + for (; eipS <= eipE; eipS++) { + ch = getUChar(eipS); + uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t3); + uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, ch-0x58); + uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1); + uLiteral(cb, 4); + SMC_IF_ALL(cb); + if (dis) + VG_(printf)("popl %s\n", nameIReg(4,ch-0x58)); + } + uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP); + eip = eipE + 1; + break; + } + + case 0x5C: /* POP eSP */ + normal_pop_case: t1 = newTemp(cb); t2 = newTemp(cb); uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2); uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1); @@ -3780,11 +3812,46 @@ static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd ) case 0x50: /* PUSH eAX */ case 0x51: /* PUSH eCX */ case 0x52: /* PUSH eDX */ - case 0x54: /* PUSH eSP */ case 0x53: /* PUSH eBX */ case 0x55: /* PUSH eBP */ case 0x56: /* PUSH eSI */ case 0x57: /* PUSH eDI */ + { Int n_pushes; + Addr eipS, eipE; + UChar ch; + if (sz != 4) goto normal_push_case; + /* eip points at first push insn + 1. Make eipS and eipE + bracket the sequence. */ + eipE = eipS = eip - 1; + while (True) { + ch = getUChar(eipE+1); + if (ch < 0x50 || ch > 0x57 || ch == 0x54) break; + eipE++; + } + n_pushes = eipE - eipS + 1; + if (0 && n_pushes > 1) VG_(printf)("%d pushes\n", n_pushes); + t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb); + uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1); + uInstr2(cb, MOV, 4, TempReg, t1, TempReg, t2); + uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2); + uLiteral(cb, 4 * n_pushes); + uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP); + for (; eipS <= eipE; eipS++) { + ch = getUChar(eipS); + uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1); + uLiteral(cb, 4); + uInstr2(cb, GET, 4, ArchReg, ch-0x50, TempReg, t3); + uInstr2(cb, STORE, 4, TempReg, t3, TempReg, t1); + SMC_IF_ALL(cb); + if (dis) + VG_(printf)("pushl %s\n", nameIReg(4,ch-0x50)); + } + eip = eipE + 1; + break; + } + + case 0x54: /* PUSH eSP */ + normal_push_case: /* This is the Right Way, in that the value to be pushed is established before %esp is changed, so that pushl %esp correctly pushes the old value. */ diff --git a/vg_memory.c b/vg_memory.c index 59d183b48a..a6a2c5d929 100644 --- a/vg_memory.c +++ b/vg_memory.c @@ -99,7 +99,7 @@ #ifdef VG_PROFILE_MEMORY -#define N_PROF_EVENTS 120 +#define N_PROF_EVENTS 150 static UInt event_ctr[N_PROF_EVENTS]; @@ -204,16 +204,23 @@ static void init_prof_mem ( void ) { } 101 handle_esp_assignment 102 handle_esp_assignment(-4) 103 handle_esp_assignment(+4) - 104 handle_esp_assignment(+16) - 105 handle_esp_assignment(-12) - 106 handle_esp_assignment(+8) - 107 handle_esp_assignment(-8) - - 110 vg_handle_esp_assignment_SLOWLY - 111 vg_handle_esp_assignment_SLOWLY(normal; move down) - 112 vg_handle_esp_assignment_SLOWLY(normal; move up) - 113 vg_handle_esp_assignment_SLOWLY(normal) - 114 vg_handle_esp_assignment_SLOWLY(>= HUGE_DELTA) + 104 handle_esp_assignment(-12) + 105 handle_esp_assignment(-8) + 106 handle_esp_assignment(+16) + 107 handle_esp_assignment(+12) + 108 handle_esp_assignment(0) + 109 handle_esp_assignment(+8) + 110 handle_esp_assignment(-16) + 111 handle_esp_assignment(+20) + 112 handle_esp_assignment(-20) + 113 handle_esp_assignment(+24) + 114 handle_esp_assignment(-24) + + 120 vg_handle_esp_assignment_SLOWLY + 121 vg_handle_esp_assignment_SLOWLY(normal; move down) + 122 vg_handle_esp_assignment_SLOWLY(normal; move up) + 123 vg_handle_esp_assignment_SLOWLY(normal) + 124 vg_handle_esp_assignment_SLOWLY(>= HUGE_DELTA) */ /*------------------------------------------------------------*/ @@ -712,7 +719,6 @@ static __inline__ UInt shiftRight16 ( UInt x ) Under all other circumstances, it defers to the relevant _SLOWLY function, which can handle all situations. */ - UInt VG_(helperc_LOADV4) ( Addr a ) { # ifdef VG_DEBUG_MEMORY @@ -1384,9 +1390,23 @@ void VGM_(handle_esp_assignment) ( Addr new_espA ) return; } - if (delta == 16) { - /* Also surprisingly common. */ + if (delta == -12) { PROF_EVENT(104); + make_aligned_word_WRITABLE(new_esp); + make_aligned_word_WRITABLE(new_esp+4); + make_aligned_word_WRITABLE(new_esp+8); + return; + } + + if (delta == -8) { + PROF_EVENT(105); + make_aligned_word_WRITABLE(new_esp); + make_aligned_word_WRITABLE(new_esp+4); + return; + } + + if (delta == 16) { + PROF_EVENT(106); make_aligned_word_NOACCESS(old_esp); make_aligned_word_NOACCESS(old_esp+4); make_aligned_word_NOACCESS(old_esp+8); @@ -1394,27 +1414,77 @@ void VGM_(handle_esp_assignment) ( Addr new_espA ) return; } - if (delta == -12) { - PROF_EVENT(105); + if (delta == 12) { + PROF_EVENT(107); + make_aligned_word_NOACCESS(old_esp); + make_aligned_word_NOACCESS(old_esp+4); + make_aligned_word_NOACCESS(old_esp+8); + return; + } + + if (delta == 0) { + PROF_EVENT(108); + return; + } + + if (delta == 8) { + PROF_EVENT(109); + make_aligned_word_NOACCESS(old_esp); + make_aligned_word_NOACCESS(old_esp+4); + return; + } + + if (delta == -16) { + PROF_EVENT(110); make_aligned_word_WRITABLE(new_esp); make_aligned_word_WRITABLE(new_esp+4); make_aligned_word_WRITABLE(new_esp+8); + make_aligned_word_WRITABLE(new_esp+12); return; } - if (delta == 8) { - PROF_EVENT(106); + if (delta == 20) { + PROF_EVENT(111); make_aligned_word_NOACCESS(old_esp); make_aligned_word_NOACCESS(old_esp+4); + make_aligned_word_NOACCESS(old_esp+8); + make_aligned_word_NOACCESS(old_esp+12); + make_aligned_word_NOACCESS(old_esp+16); return; } - if (delta == -8) { - PROF_EVENT(107); + if (delta == -20) { + PROF_EVENT(112); make_aligned_word_WRITABLE(new_esp); make_aligned_word_WRITABLE(new_esp+4); + make_aligned_word_WRITABLE(new_esp+8); + make_aligned_word_WRITABLE(new_esp+12); + make_aligned_word_WRITABLE(new_esp+16); return; } + + if (delta == 24) { + PROF_EVENT(113); + make_aligned_word_NOACCESS(old_esp); + make_aligned_word_NOACCESS(old_esp+4); + make_aligned_word_NOACCESS(old_esp+8); + make_aligned_word_NOACCESS(old_esp+12); + make_aligned_word_NOACCESS(old_esp+16); + make_aligned_word_NOACCESS(old_esp+20); + return; + } + + if (delta == -24) { + PROF_EVENT(114); + make_aligned_word_WRITABLE(new_esp); + make_aligned_word_WRITABLE(new_esp+4); + make_aligned_word_WRITABLE(new_esp+8); + make_aligned_word_WRITABLE(new_esp+12); + make_aligned_word_WRITABLE(new_esp+16); + make_aligned_word_WRITABLE(new_esp+20); + return; + } + } # endif @@ -1431,23 +1501,23 @@ static void vg_handle_esp_assignment_SLOWLY ( Addr new_espA ) UInt old_esp = VG_(baseBlock)[VGOFF_(m_esp)]; UInt new_esp = (UInt)new_espA; Int delta = ((Int)new_esp) - ((Int)old_esp); - - PROF_EVENT(110); + // VG_(printf)("%d ", delta); + PROF_EVENT(120); if (-(VG_HUGE_DELTA) < delta && delta < VG_HUGE_DELTA) { /* "Ordinary" stack change. */ if (new_esp < old_esp) { /* Moving down; the stack is growing. */ - PROF_EVENT(111); + PROF_EVENT(121); VGM_(make_writable) ( new_esp, old_esp - new_esp ); return; } if (new_esp > old_esp) { /* Moving up; the stack is shrinking. */ - PROF_EVENT(112); + PROF_EVENT(122); VGM_(make_noaccess) ( old_esp, new_esp - old_esp ); return; } - PROF_EVENT(113); + PROF_EVENT(123); return; /* when old_esp == new_esp */ } @@ -1470,7 +1540,7 @@ static void vg_handle_esp_assignment_SLOWLY ( Addr new_espA ) Addr valid_up_to = get_page_base(new_esp) + VKI_BYTES_PER_PAGE + 0 * VKI_BYTES_PER_PAGE; ThreadState* tst = VG_(get_current_thread_state)(); - PROF_EVENT(114); + PROF_EVENT(124); if (VG_(clo_verbosity) > 1) VG_(message)(Vg_UserMsg, "Warning: client switching stacks? " "%%esp: %p --> %p", diff --git a/vg_to_ucode.c b/vg_to_ucode.c index 4be838c193..607926ed65 100644 --- a/vg_to_ucode.c +++ b/vg_to_ucode.c @@ -3704,10 +3704,42 @@ static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd ) case 0x59: /* POP eCX */ case 0x5A: /* POP eDX */ case 0x5B: /* POP eBX */ - case 0x5C: /* POP eSP */ case 0x5D: /* POP eBP */ case 0x5E: /* POP eSI */ case 0x5F: /* POP eDI */ + { Int n_pops; + Addr eipS, eipE; + UChar ch; + if (sz != 4) goto normal_pop_case; + /* eip points at first pop insn + 1. Make eipS and eipE + bracket the sequence. */ + eipE = eipS = eip - 1; + while (True) { + ch = getUChar(eipE+1); + if (ch < 0x58 || ch > 0x5F || ch == 0x5C) break; + eipE++; + } + n_pops = eipE - eipS + 1; + if (0 && n_pops > 1) VG_(printf)("%d pops\n", n_pops); + t1 = newTemp(cb); t3 = newTemp(cb); + uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1); + for (; eipS <= eipE; eipS++) { + ch = getUChar(eipS); + uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t3); + uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, ch-0x58); + uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1); + uLiteral(cb, 4); + SMC_IF_ALL(cb); + if (dis) + VG_(printf)("popl %s\n", nameIReg(4,ch-0x58)); + } + uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP); + eip = eipE + 1; + break; + } + + case 0x5C: /* POP eSP */ + normal_pop_case: t1 = newTemp(cb); t2 = newTemp(cb); uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2); uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1); @@ -3780,11 +3812,46 @@ static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd ) case 0x50: /* PUSH eAX */ case 0x51: /* PUSH eCX */ case 0x52: /* PUSH eDX */ - case 0x54: /* PUSH eSP */ case 0x53: /* PUSH eBX */ case 0x55: /* PUSH eBP */ case 0x56: /* PUSH eSI */ case 0x57: /* PUSH eDI */ + { Int n_pushes; + Addr eipS, eipE; + UChar ch; + if (sz != 4) goto normal_push_case; + /* eip points at first push insn + 1. Make eipS and eipE + bracket the sequence. */ + eipE = eipS = eip - 1; + while (True) { + ch = getUChar(eipE+1); + if (ch < 0x50 || ch > 0x57 || ch == 0x54) break; + eipE++; + } + n_pushes = eipE - eipS + 1; + if (0 && n_pushes > 1) VG_(printf)("%d pushes\n", n_pushes); + t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb); + uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1); + uInstr2(cb, MOV, 4, TempReg, t1, TempReg, t2); + uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2); + uLiteral(cb, 4 * n_pushes); + uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP); + for (; eipS <= eipE; eipS++) { + ch = getUChar(eipS); + uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1); + uLiteral(cb, 4); + uInstr2(cb, GET, 4, ArchReg, ch-0x50, TempReg, t3); + uInstr2(cb, STORE, 4, TempReg, t3, TempReg, t1); + SMC_IF_ALL(cb); + if (dis) + VG_(printf)("pushl %s\n", nameIReg(4,ch-0x50)); + } + eip = eipE + 1; + break; + } + + case 0x54: /* PUSH eSP */ + normal_push_case: /* This is the Right Way, in that the value to be pushed is established before %esp is changed, so that pushl %esp correctly pushes the old value. */