mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-11 05:55:48 +00:00
This commit introduces two new UInstructions: CCALL_1_0, CCALL_2_0.
These are the first of a generic family for calling C functions. CCALL_M_N calls a function with M word-sized arguments and N word-sized return values (N == 0 or 1, of course). All stack management is done automatically -- register saving, argument pushing, register restoring. Rough timings show it's marginally faster (~3%), probably because the instrumentation phase is slightly simpler and translations are slighly more compact. It was introduced because the way Cachegrind was calling its helper functions was not really legitimate -- it involved pushing RealRegs at a point where RealRegs shouldn't have been used. This flukily worked for Cachegrind, but caused obscure seg faults when I tried using the same technique for the DIDUCE stuff. Hence this more general approach. CCALL_M_N where M+N <= 3 are easy. More args might be done by abusing spare fields in the UInstr struct, if really necessary. But it's not, yet. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@546
This commit is contained in:
@@ -594,11 +594,6 @@ UCodeBlock* VG_(cachesim_instrument)(UCodeBlock* cb_in, Addr orig_addr)
|
||||
vg_assert(instr_size >= 1 && instr_size <= MAX_x86_INSTR_SIZE);
|
||||
vg_assert(0 != instr_addr);
|
||||
|
||||
/* Save the caller-save registers before we push our args */
|
||||
uInstr1(cb, PUSH, 4, RealReg, R_EAX);
|
||||
uInstr1(cb, PUSH, 4, RealReg, R_ECX);
|
||||
uInstr1(cb, PUSH, 4, RealReg, R_EDX);
|
||||
|
||||
if (!IS_(read) && !IS_(write)) {
|
||||
iCC* CC_ptr = (iCC*)(BBCC_ptr);
|
||||
vg_assert(INVALID_DATA_SIZE == data_size);
|
||||
@@ -608,7 +603,13 @@ UCodeBlock* VG_(cachesim_instrument)(UCodeBlock* cb_in, Addr orig_addr)
|
||||
if (!BB_seen_before)
|
||||
init_iCC(CC_ptr, instr_addr, instr_size);
|
||||
|
||||
helper = VGOFF_(cachesim_log_non_mem_instr);
|
||||
/* 1st arg: CC addr */
|
||||
t_CC_addr = newTemp(cb);
|
||||
uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_CC_addr);
|
||||
uLiteral(cb, BBCC_ptr);
|
||||
|
||||
uInstr1(cb, CCALL_1_0, 0, TempReg, t_CC_addr);
|
||||
uLiteral(cb, VGOFF_(cachesim_log_non_mem_instr));
|
||||
|
||||
} else {
|
||||
CC_type X_CC;
|
||||
@@ -639,31 +640,19 @@ UCodeBlock* VG_(cachesim_instrument)(UCodeBlock* cb_in, Addr orig_addr)
|
||||
INVALID_TEMPREG != t_write_addr);
|
||||
t_data_addr = t_read_addr;
|
||||
}
|
||||
|
||||
#undef IS_
|
||||
if (!BB_seen_before)
|
||||
init_idCC(X_CC, CC_ptr, instr_addr, instr_size, data_size);
|
||||
|
||||
/* 2nd arg: data addr */
|
||||
uInstr1(cb, PUSH, 4, TempReg, t_data_addr);
|
||||
stack_used += 4;
|
||||
/* 1st arg: CC addr */
|
||||
t_CC_addr = newTemp(cb);
|
||||
uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_CC_addr);
|
||||
uLiteral(cb, BBCC_ptr);
|
||||
|
||||
uInstr2(cb, CCALL_2_0, 0, TempReg, t_CC_addr,
|
||||
TempReg, t_data_addr);
|
||||
uLiteral(cb, VGOFF_(cachesim_log_mem_instr));
|
||||
}
|
||||
#undef IS_
|
||||
|
||||
/* 1st arg: CC addr */
|
||||
t_CC_addr = newTemp(cb);
|
||||
uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_CC_addr);
|
||||
uLiteral(cb, BBCC_ptr);
|
||||
uInstr1(cb, PUSH, 4, TempReg, t_CC_addr);
|
||||
stack_used += 4;
|
||||
|
||||
/* Call function and return. */
|
||||
uInstr1(cb, CALLM, 0, Lit16, helper);
|
||||
uInstr1(cb, CLEAR, 0, Lit16, stack_used);
|
||||
|
||||
/* Restore the caller-save registers now the call is done */
|
||||
uInstr1(cb, POP, 4, RealReg, R_EDX);
|
||||
uInstr1(cb, POP, 4, RealReg, R_ECX);
|
||||
uInstr1(cb, POP, 4, RealReg, R_EAX);
|
||||
|
||||
VG_(copyUInstr)(cb, u_in);
|
||||
|
||||
|
||||
@@ -199,6 +199,7 @@ miss_treatment: \
|
||||
if (is_miss) { MISS_TREATMENT; } \
|
||||
\
|
||||
} else { \
|
||||
VG_(printf)("addr: %x size: %u sets: %d %d", a, size, set1, set2); \
|
||||
VG_(panic)("item straddles more than two cache sets"); \
|
||||
} \
|
||||
return; \
|
||||
|
||||
@@ -1067,6 +1067,43 @@ static void synth_call_baseBlock_method ( Bool ensure_shortform,
|
||||
emit_call_star_EBP_off ( 4 * word_offset );
|
||||
}
|
||||
|
||||
static void synth_ccall_saveRegs ( void )
|
||||
{
|
||||
emit_pushv_reg ( 4, R_EAX );
|
||||
emit_pushv_reg ( 4, R_ECX );
|
||||
emit_pushv_reg ( 4, R_EDX );
|
||||
}
|
||||
|
||||
static void synth_ccall_pushOneArg ( Int r1 )
|
||||
{
|
||||
emit_pushv_reg ( 4, r1 );
|
||||
}
|
||||
|
||||
static void synth_ccall_pushTwoArgs ( Int r1, Int r2 )
|
||||
{
|
||||
/* must push in reverse order */
|
||||
emit_pushv_reg ( 4, r2 );
|
||||
emit_pushv_reg ( 4, r1 );
|
||||
}
|
||||
|
||||
/* Synthesise a call to *baseBlock[offset], ie,
|
||||
call * (4 x offset)(%ebp) with arguments
|
||||
*/
|
||||
static void synth_ccall_call_clearStack_restoreRegs ( Int word_offset,
|
||||
UInt n_args_bytes )
|
||||
{
|
||||
vg_assert(word_offset >= 0);
|
||||
vg_assert(word_offset < VG_BASEBLOCK_WORDS);
|
||||
vg_assert(n_args_bytes <= 12); /* Max 3 word-sized args */
|
||||
vg_assert(0 == (n_args_bytes & 0x3)); /* Divisible by four */
|
||||
|
||||
emit_call_star_EBP_off ( 4 * word_offset );
|
||||
if ( 0 != n_args_bytes )
|
||||
emit_add_lit_to_esp ( n_args_bytes );
|
||||
emit_popv_reg ( 4, R_EDX );
|
||||
emit_popv_reg ( 4, R_ECX );
|
||||
emit_popv_reg ( 4, R_EAX );
|
||||
}
|
||||
|
||||
static void load_ebp_from_JmpKind ( JmpKind jmpkind )
|
||||
{
|
||||
@@ -2524,6 +2561,26 @@ static void emitUInstr ( Int i, UInstr* u )
|
||||
emit_put_eflags();
|
||||
break;
|
||||
|
||||
case CCALL_1_0:
|
||||
vg_assert(u->tag1 == RealReg);
|
||||
vg_assert(u->tag2 == NoValue);
|
||||
vg_assert(u->size == 0);
|
||||
|
||||
synth_ccall_saveRegs();
|
||||
synth_ccall_pushOneArg ( u->val1 );
|
||||
synth_ccall_call_clearStack_restoreRegs ( u->lit32, 4 );
|
||||
break;
|
||||
|
||||
case CCALL_2_0:
|
||||
vg_assert(u->tag1 == RealReg);
|
||||
vg_assert(u->tag2 == RealReg);
|
||||
vg_assert(u->size == 0);
|
||||
|
||||
synth_ccall_saveRegs();
|
||||
synth_ccall_pushTwoArgs ( u->val1, u->val2 );
|
||||
synth_ccall_call_clearStack_restoreRegs ( u->lit32, 8 );
|
||||
break;
|
||||
|
||||
case CLEAR:
|
||||
vg_assert(u->tag1 == Lit16);
|
||||
vg_assert(u->tag2 == NoValue);
|
||||
|
||||
@@ -1066,6 +1066,10 @@ typedef
|
||||
PUSH, POP, CLEAR, /* Add/remove/zap args for helpers. */
|
||||
CALLM, /* call to a machine-code helper */
|
||||
|
||||
/* for calling C functions -- CCALL_M_N passes M arguments and returns N
|
||||
* (0 or 1) return values */
|
||||
CCALL_1_0, CCALL_2_0,
|
||||
|
||||
/* Hack for translating string (REP-) insns. Jump to literal if
|
||||
TempReg/RealReg is zero. */
|
||||
JIFZ,
|
||||
|
||||
@@ -521,6 +521,10 @@ Bool VG_(saneUInstr) ( Bool beforeRA, UInstr* u )
|
||||
return CC0 && Ls1 && N2 && SZ0 && N3;
|
||||
case CALLM:
|
||||
return SZ0 && Ls1 && N2 && N3;
|
||||
case CCALL_1_0:
|
||||
return SZ0 && CC0 && TR1 && N2 && N3;
|
||||
case CCALL_2_0:
|
||||
return SZ0 && CC0 && TR1 && TR2 && N3;
|
||||
case PUSH: case POP:
|
||||
return CC0 && TR1 && N2 && N3;
|
||||
case AND: case OR:
|
||||
@@ -802,6 +806,8 @@ Char* VG_(nameUOpcode) ( Bool upper, Opcode opc )
|
||||
case JMP: return "J" ;
|
||||
case JIFZ: return "JIFZ" ;
|
||||
case CALLM: return "CALLM";
|
||||
case CCALL_1_0: return "CCALL_1_0";
|
||||
case CCALL_2_0: return "CCALL_2_0";
|
||||
case PUSH: return "PUSH" ;
|
||||
case POP: return "POP" ;
|
||||
case CLEAR: return "CLEAR";
|
||||
@@ -928,6 +934,20 @@ void VG_(ppUInstr) ( Int instrNo, UInstr* u )
|
||||
ppUOperand(u, 1, u->size, False);
|
||||
break;
|
||||
|
||||
case CCALL_1_0:
|
||||
VG_(printf)(" ");
|
||||
ppUOperand(u, 1, 0, False);
|
||||
VG_(printf)(" (%u)", u->lit32);
|
||||
break;
|
||||
|
||||
case CCALL_2_0:
|
||||
VG_(printf)(" ");
|
||||
ppUOperand(u, 1, 0, False);
|
||||
VG_(printf)(", ");
|
||||
ppUOperand(u, 2, 0, False);
|
||||
VG_(printf)(" (%u)", u->lit32);
|
||||
break;
|
||||
|
||||
case JIFZ:
|
||||
VG_(printf)("\t");
|
||||
ppUOperand(u, 1, u->size, False);
|
||||
@@ -1050,13 +1070,13 @@ Int getTempUsage ( UInstr* u, TempUse* arr )
|
||||
case GET: WR(2); break;
|
||||
case PUT: RD(1); break;
|
||||
case LOAD: RD(1); WR(2); break;
|
||||
case STORE: RD(1); RD(2); break;
|
||||
case STORE: case CCALL_2_0: RD(1); RD(2); break;
|
||||
case MOV: RD(1); WR(2); break;
|
||||
|
||||
case JMP: RD(1); break;
|
||||
case CLEAR: case CALLM: break;
|
||||
|
||||
case PUSH: RD(1); break;
|
||||
case PUSH: case CCALL_1_0: RD(1); break;
|
||||
case POP: WR(1); break;
|
||||
|
||||
case TAG2:
|
||||
|
||||
@@ -594,11 +594,6 @@ UCodeBlock* VG_(cachesim_instrument)(UCodeBlock* cb_in, Addr orig_addr)
|
||||
vg_assert(instr_size >= 1 && instr_size <= MAX_x86_INSTR_SIZE);
|
||||
vg_assert(0 != instr_addr);
|
||||
|
||||
/* Save the caller-save registers before we push our args */
|
||||
uInstr1(cb, PUSH, 4, RealReg, R_EAX);
|
||||
uInstr1(cb, PUSH, 4, RealReg, R_ECX);
|
||||
uInstr1(cb, PUSH, 4, RealReg, R_EDX);
|
||||
|
||||
if (!IS_(read) && !IS_(write)) {
|
||||
iCC* CC_ptr = (iCC*)(BBCC_ptr);
|
||||
vg_assert(INVALID_DATA_SIZE == data_size);
|
||||
@@ -608,7 +603,13 @@ UCodeBlock* VG_(cachesim_instrument)(UCodeBlock* cb_in, Addr orig_addr)
|
||||
if (!BB_seen_before)
|
||||
init_iCC(CC_ptr, instr_addr, instr_size);
|
||||
|
||||
helper = VGOFF_(cachesim_log_non_mem_instr);
|
||||
/* 1st arg: CC addr */
|
||||
t_CC_addr = newTemp(cb);
|
||||
uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_CC_addr);
|
||||
uLiteral(cb, BBCC_ptr);
|
||||
|
||||
uInstr1(cb, CCALL_1_0, 0, TempReg, t_CC_addr);
|
||||
uLiteral(cb, VGOFF_(cachesim_log_non_mem_instr));
|
||||
|
||||
} else {
|
||||
CC_type X_CC;
|
||||
@@ -639,31 +640,19 @@ UCodeBlock* VG_(cachesim_instrument)(UCodeBlock* cb_in, Addr orig_addr)
|
||||
INVALID_TEMPREG != t_write_addr);
|
||||
t_data_addr = t_read_addr;
|
||||
}
|
||||
|
||||
#undef IS_
|
||||
if (!BB_seen_before)
|
||||
init_idCC(X_CC, CC_ptr, instr_addr, instr_size, data_size);
|
||||
|
||||
/* 2nd arg: data addr */
|
||||
uInstr1(cb, PUSH, 4, TempReg, t_data_addr);
|
||||
stack_used += 4;
|
||||
/* 1st arg: CC addr */
|
||||
t_CC_addr = newTemp(cb);
|
||||
uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_CC_addr);
|
||||
uLiteral(cb, BBCC_ptr);
|
||||
|
||||
uInstr2(cb, CCALL_2_0, 0, TempReg, t_CC_addr,
|
||||
TempReg, t_data_addr);
|
||||
uLiteral(cb, VGOFF_(cachesim_log_mem_instr));
|
||||
}
|
||||
#undef IS_
|
||||
|
||||
/* 1st arg: CC addr */
|
||||
t_CC_addr = newTemp(cb);
|
||||
uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_CC_addr);
|
||||
uLiteral(cb, BBCC_ptr);
|
||||
uInstr1(cb, PUSH, 4, TempReg, t_CC_addr);
|
||||
stack_used += 4;
|
||||
|
||||
/* Call function and return. */
|
||||
uInstr1(cb, CALLM, 0, Lit16, helper);
|
||||
uInstr1(cb, CLEAR, 0, Lit16, stack_used);
|
||||
|
||||
/* Restore the caller-save registers now the call is done */
|
||||
uInstr1(cb, POP, 4, RealReg, R_EDX);
|
||||
uInstr1(cb, POP, 4, RealReg, R_ECX);
|
||||
uInstr1(cb, POP, 4, RealReg, R_EAX);
|
||||
|
||||
VG_(copyUInstr)(cb, u_in);
|
||||
|
||||
|
||||
@@ -199,6 +199,7 @@ miss_treatment: \
|
||||
if (is_miss) { MISS_TREATMENT; } \
|
||||
\
|
||||
} else { \
|
||||
VG_(printf)("addr: %x size: %u sets: %d %d", a, size, set1, set2); \
|
||||
VG_(panic)("item straddles more than two cache sets"); \
|
||||
} \
|
||||
return; \
|
||||
|
||||
@@ -1067,6 +1067,43 @@ static void synth_call_baseBlock_method ( Bool ensure_shortform,
|
||||
emit_call_star_EBP_off ( 4 * word_offset );
|
||||
}
|
||||
|
||||
static void synth_ccall_saveRegs ( void )
|
||||
{
|
||||
emit_pushv_reg ( 4, R_EAX );
|
||||
emit_pushv_reg ( 4, R_ECX );
|
||||
emit_pushv_reg ( 4, R_EDX );
|
||||
}
|
||||
|
||||
static void synth_ccall_pushOneArg ( Int r1 )
|
||||
{
|
||||
emit_pushv_reg ( 4, r1 );
|
||||
}
|
||||
|
||||
static void synth_ccall_pushTwoArgs ( Int r1, Int r2 )
|
||||
{
|
||||
/* must push in reverse order */
|
||||
emit_pushv_reg ( 4, r2 );
|
||||
emit_pushv_reg ( 4, r1 );
|
||||
}
|
||||
|
||||
/* Synthesise a call to *baseBlock[offset], ie,
|
||||
call * (4 x offset)(%ebp) with arguments
|
||||
*/
|
||||
static void synth_ccall_call_clearStack_restoreRegs ( Int word_offset,
|
||||
UInt n_args_bytes )
|
||||
{
|
||||
vg_assert(word_offset >= 0);
|
||||
vg_assert(word_offset < VG_BASEBLOCK_WORDS);
|
||||
vg_assert(n_args_bytes <= 12); /* Max 3 word-sized args */
|
||||
vg_assert(0 == (n_args_bytes & 0x3)); /* Divisible by four */
|
||||
|
||||
emit_call_star_EBP_off ( 4 * word_offset );
|
||||
if ( 0 != n_args_bytes )
|
||||
emit_add_lit_to_esp ( n_args_bytes );
|
||||
emit_popv_reg ( 4, R_EDX );
|
||||
emit_popv_reg ( 4, R_ECX );
|
||||
emit_popv_reg ( 4, R_EAX );
|
||||
}
|
||||
|
||||
static void load_ebp_from_JmpKind ( JmpKind jmpkind )
|
||||
{
|
||||
@@ -2524,6 +2561,26 @@ static void emitUInstr ( Int i, UInstr* u )
|
||||
emit_put_eflags();
|
||||
break;
|
||||
|
||||
case CCALL_1_0:
|
||||
vg_assert(u->tag1 == RealReg);
|
||||
vg_assert(u->tag2 == NoValue);
|
||||
vg_assert(u->size == 0);
|
||||
|
||||
synth_ccall_saveRegs();
|
||||
synth_ccall_pushOneArg ( u->val1 );
|
||||
synth_ccall_call_clearStack_restoreRegs ( u->lit32, 4 );
|
||||
break;
|
||||
|
||||
case CCALL_2_0:
|
||||
vg_assert(u->tag1 == RealReg);
|
||||
vg_assert(u->tag2 == RealReg);
|
||||
vg_assert(u->size == 0);
|
||||
|
||||
synth_ccall_saveRegs();
|
||||
synth_ccall_pushTwoArgs ( u->val1, u->val2 );
|
||||
synth_ccall_call_clearStack_restoreRegs ( u->lit32, 8 );
|
||||
break;
|
||||
|
||||
case CLEAR:
|
||||
vg_assert(u->tag1 == Lit16);
|
||||
vg_assert(u->tag2 == NoValue);
|
||||
|
||||
@@ -1066,6 +1066,10 @@ typedef
|
||||
PUSH, POP, CLEAR, /* Add/remove/zap args for helpers. */
|
||||
CALLM, /* call to a machine-code helper */
|
||||
|
||||
/* for calling C functions -- CCALL_M_N passes M arguments and returns N
|
||||
* (0 or 1) return values */
|
||||
CCALL_1_0, CCALL_2_0,
|
||||
|
||||
/* Hack for translating string (REP-) insns. Jump to literal if
|
||||
TempReg/RealReg is zero. */
|
||||
JIFZ,
|
||||
|
||||
@@ -521,6 +521,10 @@ Bool VG_(saneUInstr) ( Bool beforeRA, UInstr* u )
|
||||
return CC0 && Ls1 && N2 && SZ0 && N3;
|
||||
case CALLM:
|
||||
return SZ0 && Ls1 && N2 && N3;
|
||||
case CCALL_1_0:
|
||||
return SZ0 && CC0 && TR1 && N2 && N3;
|
||||
case CCALL_2_0:
|
||||
return SZ0 && CC0 && TR1 && TR2 && N3;
|
||||
case PUSH: case POP:
|
||||
return CC0 && TR1 && N2 && N3;
|
||||
case AND: case OR:
|
||||
@@ -802,6 +806,8 @@ Char* VG_(nameUOpcode) ( Bool upper, Opcode opc )
|
||||
case JMP: return "J" ;
|
||||
case JIFZ: return "JIFZ" ;
|
||||
case CALLM: return "CALLM";
|
||||
case CCALL_1_0: return "CCALL_1_0";
|
||||
case CCALL_2_0: return "CCALL_2_0";
|
||||
case PUSH: return "PUSH" ;
|
||||
case POP: return "POP" ;
|
||||
case CLEAR: return "CLEAR";
|
||||
@@ -928,6 +934,20 @@ void VG_(ppUInstr) ( Int instrNo, UInstr* u )
|
||||
ppUOperand(u, 1, u->size, False);
|
||||
break;
|
||||
|
||||
case CCALL_1_0:
|
||||
VG_(printf)(" ");
|
||||
ppUOperand(u, 1, 0, False);
|
||||
VG_(printf)(" (%u)", u->lit32);
|
||||
break;
|
||||
|
||||
case CCALL_2_0:
|
||||
VG_(printf)(" ");
|
||||
ppUOperand(u, 1, 0, False);
|
||||
VG_(printf)(", ");
|
||||
ppUOperand(u, 2, 0, False);
|
||||
VG_(printf)(" (%u)", u->lit32);
|
||||
break;
|
||||
|
||||
case JIFZ:
|
||||
VG_(printf)("\t");
|
||||
ppUOperand(u, 1, u->size, False);
|
||||
@@ -1050,13 +1070,13 @@ Int getTempUsage ( UInstr* u, TempUse* arr )
|
||||
case GET: WR(2); break;
|
||||
case PUT: RD(1); break;
|
||||
case LOAD: RD(1); WR(2); break;
|
||||
case STORE: RD(1); RD(2); break;
|
||||
case STORE: case CCALL_2_0: RD(1); RD(2); break;
|
||||
case MOV: RD(1); WR(2); break;
|
||||
|
||||
case JMP: RD(1); break;
|
||||
case CLEAR: case CALLM: break;
|
||||
|
||||
case PUSH: RD(1); break;
|
||||
case PUSH: case CCALL_1_0: RD(1); break;
|
||||
case POP: WR(1); break;
|
||||
|
||||
case TAG2:
|
||||
|
||||
Reference in New Issue
Block a user