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:
Nicholas Nethercote
2002-07-28 09:53:34 +00:00
parent ecd4ee7a79
commit 252fb3fba9
10 changed files with 200 additions and 58 deletions

View File

@@ -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);

View File

@@ -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; \

View File

@@ -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);

View File

@@ -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,

View File

@@ -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:

View File

@@ -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);

View File

@@ -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; \

View File

@@ -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);

View File

@@ -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,

View File

@@ -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: