Bug 517567: NJ: ARM asm_arg does not handle LIR_ldq in register parameters with softfloat, r=dvander

This commit is contained in:
Andreas Gal 2009-09-21 12:35:37 -07:00
parent 22715396a4
commit 23b5f8a4b9

View File

@ -1409,72 +1409,103 @@ fsub(jsdouble x, jsdouble y)
}
JS_DEFINE_CALLINFO_2(static, DOUBLE, fsub, DOUBLE, DOUBLE, 1, 1)
// replace fpu ops with function calls
class SoftFloatFilter: public LirWriter
{
public:
SoftFloatFilter(LirWriter* out):
LirWriter(out)
{
SoftFloatFilter(LirWriter *out) : LirWriter(out)
{}
LIns *hi(LIns *q) {
return ins1(LIR_qhi, q);
}
LIns *lo(LIns *q) {
return ins1(LIR_qlo, q);
}
LIns* quadCall(const CallInfo *ci, LIns* args[]) {
LInsp qlo, qhi;
qlo = out->insCall(ci, args);
qhi = out->ins1(LIR_callh, qlo);
return out->qjoin(qlo, qhi);
}
LIns* ins1(LOpcode v, LIns* s0)
{
if (v == LIR_fneg)
return quadCall(&fneg_ci, &s0);
if (v == LIR_i2f)
return quadCall(&i2f_ci, &s0);
if (v == LIR_u2f)
return quadCall(&u2f_ci, &s0);
return out->ins1(v, s0);
}
LIns* ins2(LOpcode v, LIns* s0, LIns* s1)
{
LIns* args[2];
LIns* bv;
// change the numeric value and order of these LIR opcodes and die
if (LIR_fadd <= v && v <= LIR_fdiv) {
static const CallInfo *fmap[] = { &fadd_ci, &fsub_ci, &fmul_ci, &fdiv_ci };
args[0] = s1;
args[1] = s0;
return quadCall(fmap[v - LIR_fadd], args);
LIns *split(LIns *a) {
if (a->isQuad() && !a->isop(LIR_qjoin)) {
// all quad-sized args must be qjoin's for soft-float
a = ins2(LIR_qjoin, lo(a), hi(a));
}
if (LIR_feq <= v && v <= LIR_fge) {
static const CallInfo *fmap[] = { &fcmpeq_ci, &fcmplt_ci, &fcmpgt_ci, &fcmple_ci, &fcmpge_ci };
args[0] = s1;
args[1] = s0;
bv = out->insCall(fmap[v - LIR_feq], args);
return out->ins2(LIR_eq, bv, out->insImm(1));
}
return out->ins2(v, s0, s1);
return a;
}
LIns* insCall(const CallInfo *ci, LIns* args[])
{
// if the return type is ARGSIZE_F, we have
// to do a quadCall(qjoin(call,callh))
if ((ci->_argtypes & ARGSIZE_MASK_ANY) == ARGSIZE_F)
return quadCall(ci, args);
LIns *split(const CallInfo *call, LInsp args[]) {
LIns *lo = out->insCall(call, args);
LIns *hi = out->ins1(LIR_callh, lo);
return out->ins2(LIR_qjoin, lo, hi);
}
return out->insCall(ci, args);
LIns *fcall1(const CallInfo *call, LIns *a) {
LIns *args[] = { split(a) };
return split(call, args);
}
LIns *fcall2(const CallInfo *call, LIns *a, LIns *b) {
LIns *args[] = { split(b), split(a) };
return split(call, args);
}
LIns *fcmp(const CallInfo *call, LIns *a, LIns *b) {
LIns *args[] = { split(b), split(a) };
return out->ins2(LIR_eq, out->insCall(call, args), out->insImm(1));
}
LIns *ins1(LOpcode op, LIns *a) {
switch (op) {
case LIR_i2f:
return fcall1(&i2f_ci, a);
case LIR_u2f:
return fcall1(&u2f_ci, a);
case LIR_fneg:
return fcall1(&fneg_ci, a);
case LIR_fret:
return out->ins1(op, split(a));
default:
return out->ins1(op, a);
}
}
LIns *ins2(LOpcode op, LIns *a, LIns *b) {
switch (op) {
case LIR_fadd:
return fcall2(&fadd_ci, a, b);
case LIR_fsub:
return fcall2(&fsub_ci, a, b);
case LIR_fmul:
return fcall2(&fmul_ci, a, b);
case LIR_fdiv:
return fcall2(&fdiv_ci, a, b);
case LIR_feq:
return fcmp(&fcmpeq_ci, a, b);
case LIR_flt:
return fcmp(&fcmplt_ci, a, b);
case LIR_fgt:
return fcmp(&fcmpgt_ci, a, b);
case LIR_fle:
return fcmp(&fcmple_ci, a, b);
case LIR_fge:
return fcmp(&fcmpge_ci, a, b);
default:
;
}
return out->ins2(op, a, b);
}
LIns *insCall(const CallInfo *ci, LInsp args[]) {
uint32_t argt = ci->_argtypes;
for (uint32_t i = 0, argsizes = argt >> ARGSIZE_SHIFT; argsizes != 0; i++, argsizes >>= ARGSIZE_SHIFT)
args[i] = split(args[i]);
if ((argt & ARGSIZE_MASK_ANY) == ARGSIZE_F) {
// this function returns a double as two 32bit values, so replace
// call with qjoin(qhi(call), call)
return split(ci, args);
} else {
return out->insCall(ci, args);
}
}
};