From: Julian Seward Date: Sat, 30 Oct 2004 20:39:01 +0000 (+0000) Subject: Implement regparm (1 to 3) in the x86 back end. X-Git-Tag: svn/VALGRIND_3_0_1^2~872 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2024da422ccc29842adc8b1477da29ee98eeb70e;p=thirdparty%2Fvalgrind.git Implement regparm (1 to 3) in the x86 back end. git-svn-id: svn://svn.valgrind.org/vex/trunk@462 --- diff --git a/VEX/priv/host-x86/hdefs.c b/VEX/priv/host-x86/hdefs.c index 81935ad5ba..cb83fcc231 100644 --- a/VEX/priv/host-x86/hdefs.c +++ b/VEX/priv/host-x86/hdefs.c @@ -504,10 +504,12 @@ X86Instr* X86Instr_Push( X86RMI* src ) { i->Xin.Push.src = src; return i; } -X86Instr* X86Instr_Call ( HReg target ) { - X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); - i->tag = Xin_Call; - i->Xin.Call.target = target; +X86Instr* X86Instr_Call ( HReg target, Int regparms ) { + X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); + i->tag = Xin_Call; + i->Xin.Call.target = target; + i->Xin.Call.regparms = regparms; + vassert(regparms >= 0 && regparms <= 3); return i; } X86Instr* X86Instr_Goto ( IRJumpKind jk, X86CondCode cond, X86RI* dst ) { @@ -695,7 +697,7 @@ void ppX86Instr ( X86Instr* i ) { ppX86RMI(i->Xin.Push.src); return; case Xin_Call: - vex_printf("call *"); + vex_printf("call[%d] *", i->Xin.Call.regparms); ppHRegX86(i->Xin.Call.target); break; case Xin_Goto: @@ -875,6 +877,13 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i) addHRegUse(u, HRmWrite, hregX86_EAX()); addHRegUse(u, HRmWrite, hregX86_ECX()); addHRegUse(u, HRmWrite, hregX86_EDX()); + switch (i->Xin.Call.regparms) { + case 3: addHRegUse(u, HRmRead, hregX86_ECX()); /*fallthru*/ + case 2: addHRegUse(u, HRmRead, hregX86_EDX()); /*fallthru*/ + case 1: addHRegUse(u, HRmRead, hregX86_EAX()); break; + case 0: break; + default: vpanic("getRegUsage_X86Instr:Call:regparms"); + } return; case Xin_Goto: addRegUsage_X86RI(u, i->Xin.Goto.dst); diff --git a/VEX/priv/host-x86/hdefs.h b/VEX/priv/host-x86/hdefs.h index 768c8b9f25..e534416448 100644 --- a/VEX/priv/host-x86/hdefs.h +++ b/VEX/priv/host-x86/hdefs.h @@ -342,6 +342,7 @@ typedef } Push; struct { HReg target; + Int regparms; /* 0 .. 3 */ } Call; /* Pseudo-insn. Goto dst, on given condition (which could be Xcc_ALWAYS). Note importantly that if the jump is @@ -448,7 +449,7 @@ extern X86Instr* X86Instr_MulL ( Bool syned, X86ScalarSz, X86RM* ); extern X86Instr* X86Instr_Div ( Bool syned, X86ScalarSz, X86RM* ); extern X86Instr* X86Instr_Sh3232 ( X86ShiftOp, UInt amt, HReg src, HReg dst ); extern X86Instr* X86Instr_Push ( X86RMI* ); -extern X86Instr* X86Instr_Call ( HReg ); +extern X86Instr* X86Instr_Call ( HReg, Int ); extern X86Instr* X86Instr_Goto ( IRJumpKind, X86CondCode cond, X86RI* dst ); extern X86Instr* X86Instr_CMov32 ( X86CondCode, X86RM* src, HReg dst ); extern X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned, diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index f3466a4c79..8ddac164c0 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -269,6 +269,7 @@ static X86Instr* mk_MOVsd_RR ( HReg src, HReg dst ) return X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(src), dst); } + /* Push an arg onto the host stack, in preparation for a call to a helper function of some kind. Returns the number of 32-bit words pushed. */ @@ -298,18 +299,104 @@ static Int pushArg ( ISelEnv* env, IRExpr* arg ) static void callHelperAndClearArgs ( ISelEnv* env, IRCallee* cee, Int n_arg_ws ) { + HReg freg; + + /* Complication. Need to decide which reg to use as the fn address + pointer, in a way that doesn't trash regparm-passed + parameters. */ vassert(sizeof(HWord) == 4); + + switch (cee->regparms) { + case 0: freg = hregX86_EAX(); break; + case 1: freg = hregX86_EDX(); break; + case 2: freg = hregX86_ECX(); break; + case 3: freg = hregX86_EDI(); break; + default: vpanic("callHelperAndClearArgs(x86): > 3 regparms"); + } + addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Imm(cee->addr), - hregX86_EAX())); - addInstr(env, X86Instr_Call(hregX86_EAX())); + freg)); + addInstr(env, X86Instr_Call(freg, cee->regparms)); if (n_arg_ws > 0) addInstr(env, X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(4*n_arg_ws), hregX86_ESP())); } + +/* Do a complete function call. */ + +static +void doHelperCall ( ISelEnv* env, + Bool passBBP, IRCallee* cee, IRExpr** args ) +{ + HReg argregs[3]; + Int n_args, n_arg_ws, stack_limit, i, argreg; + + /* Marshal args for a call, do the call, and clear the stack. + Complexities to consider: + + * if passBBP is True, %ebp (the baseblock pointer) is to be + passed as the first arg. + + * If the callee claims regparmness of 1, 2 or 3, we must pass the + first 1, 2 or 3 args in registers (EAX, EDX, and ECX + respectively). To keep things relatively simple, only args of + type I32 may be passed as regparms -- just bomb out if anything + else turns up. Clearly this depends on the front ends not + trying to pass any other types as regparms. + */ + + vassert(cee->regparms >= 0 && cee->regparms <= 3); + + n_args = n_arg_ws = 0; + while (args[n_args]) n_args++; + + stack_limit = cee->regparms; + if (cee->regparms > 0 && passBBP) stack_limit--; + + /* Push the stack-passed args */ + for (i = n_args-1; i >= stack_limit; i--) + n_arg_ws += pushArg(env, args[i]); + + /* args [stack_limit-1 .. 0] and possibly %ebp are to be passed in + registers. */ + vassert(stack_limit + (passBBP ? 1 : 0) == cee->regparms); + + if (cee->regparms > 0) { + /* deal with regparms, not forgetting %ebp if needed. */ + argregs[0] = hregX86_EAX(); + argregs[1] = hregX86_EDX(); + argregs[2] = hregX86_ECX(); + argreg = cee->regparms; + + for (i = stack_limit-1; i >= 0; i--) { + argreg--; + vassert(argreg >= 0); + vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32); + addInstr(env, X86Instr_Alu32R(Xalu_MOV, + iselIntExpr_RMI(env, args[i]), + argregs[argreg])); + } + if (passBBP) { + vassert(argreg == 1); + addInstr(env, mk_MOVsd_RR( hregX86_EBP(), argregs[0])); + } + } else { + /* No regparms. Heave %ebp on the stack if needed. */ + if (passBBP) { + addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP()))); + n_arg_ws++; + } + } + + /* call the helper, and get the args off the stack afterwards. */ + callHelperAndClearArgs( env, cee, n_arg_ws ); +} + + /* Given a guest-state array descriptor, an index expression and a bias, generate an X86AMode holding the relevant guest state offset. */ @@ -862,7 +949,6 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) /* --------- CCALL --------- */ case Iex_CCall: { - Int i, n_args, n_arg_ws; HReg dst = newVRegI(env); vassert(ty == Ity_I32); @@ -871,15 +957,8 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) if (e->Iex.CCall.retty != Ity_I32) goto irreducible; - /* push args on the stack, right to left. */ - n_arg_ws = n_args = 0; - while (e->Iex.CCall.args[n_args]) n_args++; - - for (i = n_args-1; i >= 0; i--) - n_arg_ws += pushArg(env, e->Iex.CCall.args[i]); - - /* call the helper, and get the args off the stack afterwards. */ - callHelperAndClearArgs( env, e->Iex.CCall.cee, n_arg_ws ); + /* Marshal args, do the call, clear stack. */ + doHelperCall( env, False, e->Iex.CCall.cee, e->Iex.CCall.args ); addInstr(env, mk_MOVsd_RR(hregX86_EAX(), dst)); return dst; @@ -1602,19 +1681,11 @@ static void iselIntExpr64_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e ) /* --------- CCALL --------- */ if (e->tag == Iex_CCall) { - Int i, n_args, n_arg_ws; - HReg tLo = newVRegI(env); - HReg tHi = newVRegI(env); - - /* push args on the stack, right to left. */ - n_arg_ws = n_args = 0; - while (e->Iex.CCall.args[n_args]) n_args++; - - for (i = n_args-1; i >= 0; i--) - n_arg_ws += pushArg(env, e->Iex.CCall.args[i]); + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); - /* call the helper, and get the args off the stack afterwards. */ - callHelperAndClearArgs( env, e->Iex.CCall.cee, n_arg_ws ); + /* Marshal args, do the call, clear stack. */ + doHelperCall( env, False, e->Iex.CCall.cee, e->Iex.CCall.args ); addInstr(env, mk_MOVsd_RR(hregX86_EDX(), tHi)); addInstr(env, mk_MOVsd_RR(hregX86_EAX(), tLo)); @@ -2112,28 +2183,16 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) /* --------- Call to DIRTY helper --------- */ case Ist_Dirty: { - Int i, n_arg_ws, n_args; IRType retty; IRDirty* d = stmt->Ist.Dirty.details; - - /* push args on the stack, right to left. */ - n_arg_ws = n_args = 0; - while (d->args[n_args] != NULL) n_args++; - - for (i = n_args-1; i >= 0; i--) - n_arg_ws += pushArg(env, d->args[i]); + Bool passBBP = False; if (d->nFxState == 0) vassert(!d->needsBBP); - if (d->nFxState > 0 && d->needsBBP) { - /* If the helper claims it accesses guest state, give it a - first argument which is the guest state pointer (%ebp). */ - addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP()))); - n_arg_ws++; - } + passBBP = d->nFxState > 0 && d->needsBBP; - /* call the helper, and get the args off the stack afterwards. */ - callHelperAndClearArgs( env, d->cee, n_arg_ws ); + /* Marshal args, do the call, clear stack. */ + doHelperCall( env, passBBP, d->cee, d->args ); /* Now figure out what to do with the returned value, if any. */ if (d->tmp == INVALID_IRTEMP) diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index 19b30ec686..68636cc132 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -51,8 +51,8 @@ void ppIRConst ( IRConst* con ) void ppIRCallee ( IRCallee* ce ) { vex_printf("%s", ce->name); - if (ce->regparm > 0) - vex_printf("[%d]", ce->regparm); + if (ce->regparms > 0) + vex_printf("[%d]", ce->regparms); vex_printf("{%p}", (void*)ce->addr); } @@ -465,13 +465,13 @@ IRConst* IRConst_F64i ( ULong f64i ) /* Constructors -- IRCallee */ -IRCallee* mkIRCallee ( Int regparm, Char* name, HWord addr ) +IRCallee* mkIRCallee ( Int regparms, Char* name, HWord addr ) { IRCallee* ce = LibVEX_Alloc(sizeof(IRCallee)); - ce->regparm = regparm; - ce->name = name; - ce->addr = addr; - vassert(regparm >= 0); + ce->regparms = regparms; + ce->name = name; + ce->addr = addr; + vassert(regparms >= 0 && regparms <= 3); vassert(name != NULL); vassert(addr != 0); return ce; @@ -749,7 +749,7 @@ IRConst* dopyIRConst ( IRConst* c ) IRCallee* dopyIRCallee ( IRCallee* ce ) { - return mkIRCallee(ce->regparm, ce->name, ce->addr); + return mkIRCallee(ce->regparms, ce->name, ce->addr); } IRArray* dopyIRArray ( IRArray* d ) @@ -1180,7 +1180,7 @@ static Bool saneIRCallee ( IRCallee* cee ) return False; if (cee->addr == 0) return False; - if (cee->regparm < 0 || cee->regparm > 3) + if (cee->regparms < 0 || cee->regparms > 3) return False; return True; } diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index a6130d62c4..0b7e0871bc 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -73,7 +73,7 @@ extern Bool eqIRConst ( IRConst*, IRConst* ); /* ------------------ Call targets ------------------ */ /* Describes a helper function to call. The name part is purely for - pretty printing and not actually used. regparm=n tells the back + pretty printing and not actually used. regparms=n tells the back end that the callee has been declared "__attribute__((regparm(n)))". On some targets (x86) the back end will need to construct a non-standard sequence to call a function @@ -81,13 +81,13 @@ extern Bool eqIRConst ( IRConst*, IRConst* ); typedef struct { - Int regparm; + Int regparms; Char* name; HWord addr; } IRCallee; -extern IRCallee* mkIRCallee ( Int regparm, Char* name, HWord addr ); +extern IRCallee* mkIRCallee ( Int regparms, Char* name, HWord addr ); extern IRCallee* dopyIRCallee ( IRCallee* );