return i;
}
ARMInstr* ARMInstr_Call ( ARMCondCode cond, HWord target, Int nArgRegs,
- RetLoc rloc ) {
+ RetLoc rloc, IRDefault dflt ) {
ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
i->tag = ARMin_Call;
i->ARMin.Call.cond = cond;
i->ARMin.Call.target = target;
i->ARMin.Call.nArgRegs = nArgRegs;
i->ARMin.Call.rloc = rloc;
+ i->ARMin.Call.dflt = dflt;
vassert(rloc != RetLocINVALID);
return i;
}
vex_printf("0x%lx [nArgRegs=%d, ",
i->ARMin.Call.target, i->ARMin.Call.nArgRegs);
ppRetLoc(i->ARMin.Call.rloc);
+ if (i->ARMin.Call.dflt != Idflt_None) {
+ vex_printf(", ");
+ ppIRDefault(i->ARMin.Call.dflt);
+ }
vex_printf("]");
return;
case ARMin_Mul:
// preElse:
// b after:
// else:
- // mvn r0, #0 // possibly
- // mvn r1, #0 // possibly
+ // {mov,mvn} r0, #0 // possibly
+ // {mov,mvn} r1, #0 // possibly
// after:
+ /* Since we're generating default-return code in the else:
+ clause, there had better be a sane default-value
+ specification. */
+ vassert(i->ARMin.Call.dflt == Idflt_Zeroes
+ || i->ARMin.Call.dflt == Idflt_Ones);
+
// before:
UInt* pBefore = p;
= XX______(1 ^ i->ARMin.Call.cond, X1010) | (delta & 0xFFFFFF);
/* Do the 'else' actions */
+ /* Useful:
+ e3a00000 mov r0, #0
+ e3a01000 mov r1, #0
+ e3e00000 mvn r0, #0
+ e3e01000 mvn r1, #0
+ */
switch (i->ARMin.Call.rloc) {
- case RetLocInt:
- *p++ = 0xE3E00000; break; // mvn r0, #0
- case RetLoc2Int:
- // mvn r0, #0 ; mvn r1, #0
- vassert(0); //ATC
- *p++ = 0xE3E00000; *p++ = 0xE3E01000; break;
+ case RetLocInt: {
+ switch (i->ARMin.Call.dflt) {
+ case Idflt_Ones: *p++ = 0xE3E00000; break; // mvn r0, #0
+ case Idflt_Zeroes: *p++ = 0xE3A00000; break; // mov r0, #0
+ default: goto elsefail;
+ }
+ break;
+ }
+ case RetLoc2Int: {
+ if (i->ARMin.Call.dflt == Idflt_Ones) {
+ // mvn r0, #0 ; mvn r1, #0
+ vassert(0); //ATC
+ *p++ = 0xE3E00000; *p++ = 0xE3E01000; break;
+ }
+ goto elsefail;
+ }
case RetLocNone:
case RetLocINVALID:
default:
+ elsefail:
vassert(0);
}
HWord target;
Int nArgRegs; /* # regs carrying args: 0 .. 4 */
RetLoc rloc; /* where the return value will be */
+ IRDefault dflt; /* default return, if conditional */
} Call;
/* (PLAIN) 32 * 32 -> 32: r0 = r2 * r3
(ZX) 32 *u 32 -> 64: r1:r0 = r2 *u r3
ARMCondCode cond, IRJumpKind jk );
extern ARMInstr* ARMInstr_CMov ( ARMCondCode, HReg dst, ARMRI84* src );
extern ARMInstr* ARMInstr_Call ( ARMCondCode, HWord, Int nArgRegs,
- RetLoc rloc );
+ RetLoc rloc, IRDefault dflt );
extern ARMInstr* ARMInstr_Mul ( ARMMulOp op );
extern ARMInstr* ARMInstr_LdrEX ( Int szB );
extern ARMInstr* ARMInstr_StrEX ( Int szB );
Bool doHelperCall ( ISelEnv* env,
Bool passBBP,
IRExpr* guard, IRCallee* cee, IRExpr** args,
- RetLoc rloc )
+ RetLoc rloc, IRDefault dflt )
{
ARMCondCode cc;
HReg argregs[ARM_N_ARGREGS];
values. But that's too much hassle. */
/* Finally, the call itself. */
- addInstr(env, ARMInstr_Call( cc, target, nextArgReg, rloc ));
+ addInstr(env, ARMInstr_Call( cc, target, nextArgReg, rloc, dflt ));
return True; /* success */
}
addInstr(env, mk_iMOVds_RR(hregARM_R0(), regL));
addInstr(env, mk_iMOVds_RR(hregARM_R1(), regR));
addInstr(env, ARMInstr_Call( ARMcc_AL, (HWord)Ptr_to_ULong(fn),
- 2, RetLocInt ));
+ 2, RetLocInt, Idflt_None ));
addInstr(env, mk_iMOVds_RR(res, hregARM_R0()));
return res;
}
HReg res = newVRegI(env);
addInstr(env, mk_iMOVds_RR(hregARM_R0(), arg));
addInstr(env, ARMInstr_Call( ARMcc_AL, (HWord)Ptr_to_ULong(fn),
- 1, RetLocInt ));
+ 1, RetLocInt, Idflt_None ));
addInstr(env, mk_iMOVds_RR(res, hregARM_R0()));
return res;
}
/* Marshal args, do the call, clear stack. */
Bool ok = doHelperCall( env, False,
NULL, e->Iex.CCall.cee, e->Iex.CCall.args,
- RetLocInt );
+ RetLocInt, Idflt_None );
if (ok) {
addInstr(env, mk_iMOVds_RR(dst, hregARM_R0()));
return dst;
if (rloc == RetLocINVALID)
break; /* will go to stmt_fail: */
- Bool ok = doHelperCall( env, passBBP, d->guard, d->cee, d->args, rloc );
+ Bool ok = doHelperCall( env, passBBP, d->guard, d->cee, d->args,
+ rloc, d->dflt );
if (!ok)
break; /* will go to stmt_fail: */