}
MIPSInstr *MIPSInstr_Call(MIPSCondCode cond, Addr32 target, UInt argiregs,
- HReg src)
+ HReg src, RetLoc rloc)
{
UInt mask;
MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
i->Min.Call.target = target;
i->Min.Call.argiregs = argiregs;
i->Min.Call.src = src;
+ i->Min.Call.rloc = rloc;
/* Only r4 .. r7 inclusive may be used as arg regs. Hence: */
mask = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7);
vassert(0 == (argiregs & ~mask));
+ vassert(rloc != RetLocINVALID);
return i;
}
-MIPSInstr *MIPSInstr_CallAlways(MIPSCondCode cond, Addr32 target, UInt argiregs)
+MIPSInstr *MIPSInstr_CallAlways(MIPSCondCode cond, Addr32 target, UInt argiregs,
+ RetLoc rloc)
{
UInt mask;
MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
i->Min.Call.cond = cond;
i->Min.Call.target = target;
i->Min.Call.argiregs = argiregs;
+ i->Min.Call.rloc = rloc;
/* Only r4 .. r7 inclusive may be used as arg regs. Hence: */
mask = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7);
vassert(0 == (argiregs & ~mask));
+ vassert(rloc != RetLocINVALID);
return i;
}
vex_printf(",");
}
}
+ vex_printf(",");
+ ppRetLoc(i->Min.Call.rloc);
vex_printf("] }");
break;
}
}
case Min_Call: {
+ if (i->Min.Call.cond != MIPScc_AL && i->Min.Call.rloc != RetLocNone) {
+ /* The call might not happen (it isn't unconditional) and
+ it returns a result. In this case we will need to
+ generate a control flow diamond to put 0x555..555 in
+ the return register(s) in the case where the call
+ doesn't happen. If this ever becomes necessary, maybe
+ copy code from the ARM equivalent. Until that day,
+ just give up. */
+ goto bad;
+ }
MIPSCondCode cond = i->Min.Call.cond;
UInt r_dst = 25; /* using %r25 as address temporary -
see getRegUsage_MIPSInstr */
Addr32 target;
UInt argiregs;
HReg src;
+ RetLoc rloc; /* where the return value will be */
} Call;
/* Update the guest EIP value, then exit requesting to chain
to it. May be conditional. Urr, use of Addr32 implicitly
extern MIPSInstr *MIPSInstr_StoreC(UChar sz, MIPSAMode * dst, HReg src,
Bool mode64);
-extern MIPSInstr *MIPSInstr_Call(MIPSCondCode, Addr32, UInt, HReg);
-extern MIPSInstr *MIPSInstr_CallAlways(MIPSCondCode, Addr32, UInt);
+extern MIPSInstr *MIPSInstr_Call(MIPSCondCode, Addr32, UInt, HReg, RetLoc);
+extern MIPSInstr *MIPSInstr_CallAlways(MIPSCondCode, Addr32, UInt, RetLoc);
extern MIPSInstr *MIPSInstr_XDirect(Addr32 dstGA, MIPSAMode* amPC,
MIPSCondCode cond, Bool toFastEP);
call is unconditional. */
static void doHelperCall(ISelEnv * env, Bool passBBP, IRExpr * guard,
- IRCallee * cee, IRExpr ** args)
+ IRCallee * cee, IRExpr ** args, RetLoc rloc)
{
MIPSCondCode cc;
HReg argregs[MIPS_N_REGPARMS];
/* Finally, the call itself. */
if (mode64)
if (cc == MIPScc_AL) {
- addInstr(env, MIPSInstr_CallAlways(cc, target, argiregs));
+ addInstr(env, MIPSInstr_CallAlways(cc, target, argiregs, rloc));
} else {
- addInstr(env, MIPSInstr_Call(cc, target, argiregs, src));
+ addInstr(env, MIPSInstr_Call(cc, target, argiregs, src, rloc));
} else if (cc == MIPScc_AL) {
- addInstr(env, MIPSInstr_CallAlways(cc, (Addr32) target, argiregs));
+ addInstr(env, MIPSInstr_CallAlways(cc, (Addr32) target, argiregs, rloc));
} else {
- addInstr(env, MIPSInstr_Call(cc, (Addr32) target, argiregs, src));
+ addInstr(env, MIPSInstr_Call(cc, (Addr32) target, argiregs, src, rloc));
}
/* restore GuestStatePointer */
addInstr(env, MIPSInstr_Load(4, GuestStatePointer(mode64),
HReg r_dst = newVRegI(env);
vassert(ty == e->Iex.CCall.retty);
- /* be very restrictive for now. Only 32/64-bit ints allowed
- for args, and 32 bits for return type. */
+ /* be very restrictive for now. Only 32/64-bit ints allowed for
+ args, and 32 bits for return type. Don't forget to change
+ the RetLoc if more return types are allowed in future. */
if (e->Iex.CCall.retty != Ity_I32 && !mode64)
goto irreducible;
+ /* What's the retloc? */
+ RetLoc rloc = RetLocINVALID;
+ if (ty == Ity_I32) {
+ rloc = RetLocInt;
+ }
+ else if (ty == Ity_I64) {
+ rloc = mode64 ? RetLocInt : RetLoc2Int;
+ }
+ else {
+ goto irreducible;
+ }
+
/* Marshal args, do the call, clear stack. */
- doHelperCall(env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args);
+ doHelperCall(env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args, rloc);
addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
return r_dst;
}
/* --------- Call to DIRTY helper --------- */
case Ist_Dirty: {
- IRType retty;
IRDirty *d = stmt->Ist.Dirty.details;
Bool passBBP = False;
if (d->nFxState == 0)
vassert(!d->needsBBP);
+
passBBP = toBool(d->nFxState > 0 && d->needsBBP);
+ /* Figure out the return type, if any. */
+ IRType retty = Ity_INVALID;
+ if (d->tmp != IRTemp_INVALID)
+ retty = typeOfIRTemp(env->type_env, d->tmp);
+
+ /* Marshal args, do the call, clear stack, set the return
+ value to 0x555..555 if this is a conditional call that
+ returns a value and the call is skipped. We need to set
+ the ret-loc correctly in order to implement the IRDirty
+ semantics that the return value is 0x555..555 if the call
+ doesn't happen. */
+ RetLoc rloc = RetLocINVALID;
+ switch (retty) {
+ case Ity_INVALID: /* function doesn't return anything */
+ rloc = RetLocNone; break;
+ case Ity_I64:
+ rloc = mode64 ? RetLocInt : RetLoc2Int; break;
+ case Ity_I32: case Ity_I16: case Ity_I8:
+ rloc = RetLocInt; break;
+ default:
+ break;
+ }
+ if (rloc == RetLocINVALID)
+ break; /* will go to stmt_fail: */
+
/* Marshal args, do the call, clear stack. */
- doHelperCall(env, passBBP, d->guard, d->cee, d->args);
+ doHelperCall(env, passBBP, d->guard, d->cee, d->args, rloc);
/* Now figure out what to do with the returned value, if any. */
if (d->tmp == IRTemp_INVALID)
/* No return value. Nothing to do. */
return;
- retty = typeOfIRTemp(env->type_env, d->tmp);
if (retty == Ity_I64 && !mode64) {
HReg rHi = newVRegI(env);
HReg rLo = newVRegI(env);