return i;
}
PPC32Instr* PPC32Instr_Call ( PPC32CondCode cond,
- Addr32 target, Int regparms ) {
+ Addr32 target, UInt argiregs ) {
+ UInt mask;
PPC32Instr* i = LibVEX_Alloc(sizeof(PPC32Instr));
i->tag = Pin_Call;
i->Pin.Call.cond = cond;
i->Pin.Call.target = target;
- i->Pin.Call.regparms = regparms;
- vassert(regparms >= 0 && regparms < PPC32_N_REGPARMS);
+ i->Pin.Call.argiregs = argiregs;
+ /* Only r3 .. r10 inclusive may be used as arg regs. Hence: */
+ mask = (1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9)|(1<<10);
+ vassert(0 == (argiregs & ~mask));
return i;
}
PPC32Instr* PPC32Instr_Goto ( IRJumpKind jk,
vex_printf(",");
ppHRegPPC32(i->Pin.Div.srcR);
return;
- case Pin_Call:
+ case Pin_Call: {
+ Int n;
vex_printf("call: ");
if (i->Pin.Call.cond.test != Pct_ALWAYS) {
vex_printf("if (%s) ", showPPC32CondCode(i->Pin.Call.cond));
}
vex_printf("{ ");
ppLoadImm(hregPPC32_GPR12(), i->Pin.Call.target);
- vex_printf(" ; mtctr r12 ; bctrl [regparms=%d] }",i->Pin.Call.regparms);
+ vex_printf(" ; mtctr r12 ; bctrl [");
+ for (n = 0; n < 32; n++) {
+ if (i->Pin.Call.argiregs & (1<<n)) {
+ vex_printf("r%d", n);
+ if ((i->Pin.Call.argiregs >> n) > 1)
+ vex_printf(",");
+ }
+ }
+ vex_printf("] }");
break;
+ }
case Pin_Goto:
vex_printf("goto: ");
if (i->Pin.Goto.cond.test != Pct_ALWAYS) {
addHRegUse(u, HRmWrite, hregPPC32_GPR12());
/* Now we have to state any parameter-carrying registers
- which might be read. This depends on the regparmness. */
- switch (i->Pin.Call.regparms) {
- case 8: addHRegUse(u, HRmRead, hregPPC32_GPR10()); /*fallthru*/
- case 7: addHRegUse(u, HRmRead, hregPPC32_GPR9() ); /*fallthru*/
- case 6: addHRegUse(u, HRmRead, hregPPC32_GPR8() ); /*fallthru*/
- case 5: addHRegUse(u, HRmRead, hregPPC32_GPR7() ); /*fallthru*/
- case 4: addHRegUse(u, HRmRead, hregPPC32_GPR6() ); /*fallthru*/
- case 3: addHRegUse(u, HRmRead, hregPPC32_GPR5() ); /*fallthru*/
- case 2: addHRegUse(u, HRmRead, hregPPC32_GPR4() ); /*fallthru*/
- case 1: addHRegUse(u, HRmRead, hregPPC32_GPR3() ); /*fallthru*/
- case 0: break;
- default: vpanic("getRegUsage_PPC32Instr:Call:regparms");
- }
+ which might be read. This depends on the argiregs field. */
+ if (i->Pin.Call.argiregs & (1<<10)) addHRegUse(u, HRmRead, hregPPC32_GPR10());
+ if (i->Pin.Call.argiregs & (1<<9)) addHRegUse(u, HRmRead, hregPPC32_GPR9());
+ if (i->Pin.Call.argiregs & (1<<8)) addHRegUse(u, HRmRead, hregPPC32_GPR8());
+ if (i->Pin.Call.argiregs & (1<<7)) addHRegUse(u, HRmRead, hregPPC32_GPR7());
+ if (i->Pin.Call.argiregs & (1<<6)) addHRegUse(u, HRmRead, hregPPC32_GPR6());
+ if (i->Pin.Call.argiregs & (1<<5)) addHRegUse(u, HRmRead, hregPPC32_GPR5());
+ if (i->Pin.Call.argiregs & (1<<4)) addHRegUse(u, HRmRead, hregPPC32_GPR4());
+ if (i->Pin.Call.argiregs & (1<<3)) addHRegUse(u, HRmRead, hregPPC32_GPR3());
+
+ vassert(0 == (i->Pin.Call.argiregs
+ & ~((1<<3)|(1<<4)|(1<<5)|(1<<6)
+ |(1<<7)|(1<<8)|(1<<9)|(1<<10))));
+
/* Finally, there is the issue that the insn trashes a
register because the literal target address has to be
loaded into a register. %r12 seems a suitable victim.
HReg srcR;
} Div;
/* Pseudo-insn. Call target (an absolute address), on given
- condition (which could be Pct_ALWAYS). */
+ condition (which could be Pct_ALWAYS). argiregs indicates
+ which of r3 .. r10 carries argument values for this call,
+ using a bit mask (1<<N is set if rN holds an arg, for N in
+ 3 .. 10 inclusive). */
struct {
PPC32CondCode cond;
Addr32 target;
- Int regparms; /* 0 .. 9 */
+ UInt argiregs;
} Call;
/* Pseudo-insn. Goto dst, on given condition (which could be
Pct_ALWAYS). */
extern PPC32Instr* PPC32Instr_Unary32 ( PPC32UnaryOp op, HReg dst, HReg src );
extern PPC32Instr* PPC32Instr_MulL ( Bool syned, Bool hi32, HReg, HReg, HReg );
extern PPC32Instr* PPC32Instr_Div ( Bool syned, HReg dst, HReg srcL, HReg srcR );
-extern PPC32Instr* PPC32Instr_Call ( PPC32CondCode, Addr32, Int );
+extern PPC32Instr* PPC32Instr_Call ( PPC32CondCode, Addr32, UInt );
extern PPC32Instr* PPC32Instr_Goto ( IRJumpKind, PPC32CondCode cond, PPC32RI* dst );
extern PPC32Instr* PPC32Instr_CMov32 ( PPC32CondCode, HReg dst, PPC32RI* src );
extern PPC32Instr* PPC32Instr_Load ( UChar sz, Bool syned,
HReg tmpregs[PPC32_N_REGPARMS];
Bool go_fast;
Int n_args, i, argreg;
+ UInt argiregs;
/* Marshal args for a call and do the call.
argregs[5] = hregPPC32_GPR8();
argregs[6] = hregPPC32_GPR9();
argregs[7] = hregPPC32_GPR10();
+ argiregs = 0;
tmpregs[0] = tmpregs[1] = tmpregs[2] =
tmpregs[3] = tmpregs[4] = tmpregs[5] =
/* FAST SCHEME */
argreg = 0;
if (passBBP) {
+ argiregs |= (1 << (argreg+3));
addInstr(env, mk_iMOVds_RR( argregs[argreg], GuestStatePtr ));
argreg++;
}
vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32 ||
typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) {
+ argiregs |= (1 << (argreg+3));
addInstr(env, mk_iMOVds_RR( argregs[argreg],
iselIntExpr_R(env, args[i]) ));
} else { // Ity_I64
argreg++; // XXX: odd argreg => even rN
vassert(argreg < PPC32_N_REGPARMS-1);
iselInt64Expr(&rHi,&rLo, env, args[i]);
+ argiregs |= (1 << (argreg+3));
addInstr(env, mk_iMOVds_RR( argregs[argreg++], rHi ));
+ argiregs |= (1 << (argreg+3));
addInstr(env, mk_iMOVds_RR( argregs[argreg], rLo));
}
argreg++;
continue;
/* None of these insns, including any spill code that might
be generated, may alter the condition codes. */
+ argiregs |= (1 << (i+3));
addInstr( env, mk_iMOVds_RR( argregs[i], tmpregs[i] ) );
}
/* Finally, the call itself. */
addInstr(env, PPC32Instr_Call( cc,
(Addr32)toUInt(Ptr_to_ULong(cee->addr)),
- n_args + (passBBP ? 1 : 0) ));
+ argiregs ));
}