зеркало из https://github.com/mozilla/gecko-dev.git
[arm] fix up ARM floating point comparisons; fixes ARM trace-test (relanding)
This commit is contained in:
Родитель
937e5d9cec
Коммит
56155f4e54
|
@ -66,6 +66,13 @@ const Register Assembler::argRegs[] = { R0, R1, R2, R3 };
|
|||
const Register Assembler::retRegs[] = { R0, R1 };
|
||||
const Register Assembler::savedRegs[] = { R4, R5, R6, R7, R8, R9, R10 };
|
||||
|
||||
const char *ccName(ConditionCode cc)
|
||||
{
|
||||
const char *ccNames[] = { "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
|
||||
"hi", "ls", "ge", "lt", "gt", "le", "al", "nv" };
|
||||
return ccNames[(int)cc];
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::nInit(AvmCore*)
|
||||
{
|
||||
|
@ -1039,63 +1046,6 @@ Assembler::asm_fcmp(LInsp ins)
|
|||
Register ra = findRegFor(lhs, FpRegs);
|
||||
Register rb = findRegFor(rhs, FpRegs);
|
||||
|
||||
// We can't uniquely identify fge/fle via a single bit
|
||||
// pattern (since equality and lt/gt are separate bits);
|
||||
// so convert to the single-bit variant.
|
||||
if (op == LIR_fge) {
|
||||
Register temp = ra;
|
||||
ra = rb;
|
||||
rb = temp;
|
||||
op = LIR_flt;
|
||||
} else if (op == LIR_fle) {
|
||||
Register temp = ra;
|
||||
ra = rb;
|
||||
rb = temp;
|
||||
op = LIR_fgt;
|
||||
}
|
||||
|
||||
// There is no way to test for an unordered result using
|
||||
// the conditional form of an instruction; the encoding (C=1 V=1)
|
||||
// ends up having overlaps with a few other tests. So, test for
|
||||
// the explicit mask.
|
||||
uint8_t mask = 0x0;
|
||||
|
||||
// NZCV
|
||||
// for a valid ordered result, V is always 0 from VFP
|
||||
if (op == LIR_feq)
|
||||
// ZC // cond EQ (both equal and "not less than"
|
||||
mask = 0x6;
|
||||
else if (op == LIR_flt)
|
||||
// N // cond MI
|
||||
mask = 0x8;
|
||||
else if (op == LIR_fgt)
|
||||
// C // cond CS
|
||||
mask = 0x2;
|
||||
else
|
||||
NanoAssert(0);
|
||||
/*
|
||||
// these were converted into gt and lt above.
|
||||
if (op == LIR_fle)
|
||||
// NZ // cond LE
|
||||
mask = 0xC;
|
||||
else if (op == LIR_fge)
|
||||
// ZC // cond fail?
|
||||
mask = 0x6;
|
||||
*/
|
||||
|
||||
// TODO XXX could do this as fcmpd; fmstat; tstvs rX, #0 the tstvs
|
||||
// would reset the status bits if V (NaN flag) is set, but that
|
||||
// doesn't work for NE. For NE could teqvs rX, #1. rX needs to
|
||||
// be any register that has lsb == 0, such as sp/fp/pc.
|
||||
|
||||
// Test explicily with the full mask; if V is set, test will fail.
|
||||
// Assumption is that this will be followed up by a BEQ/BNE
|
||||
CMPi(Scratch, mask);
|
||||
// grab just the condition fields
|
||||
SHRi(Scratch, 28);
|
||||
MRS(Scratch);
|
||||
|
||||
// do the comparison and get results loaded in ARM status register
|
||||
FMSTAT();
|
||||
FCMPD(ra, rb);
|
||||
}
|
||||
|
@ -1120,10 +1070,28 @@ Assembler::asm_branch(bool branchOnFalse, LInsp cond, NIns* targ, bool isfar)
|
|||
|
||||
if (condop >= LIR_feq && condop <= LIR_fge)
|
||||
{
|
||||
if (branchOnFalse)
|
||||
JNE(targ);
|
||||
else
|
||||
JE(targ);
|
||||
ConditionCode cc = NV;
|
||||
|
||||
if (branchOnFalse) {
|
||||
switch (condop) {
|
||||
case LIR_feq: cc = NE; break;
|
||||
case LIR_flt: cc = PL; break;
|
||||
case LIR_fgt: cc = LE; break;
|
||||
case LIR_fle: cc = HI; break;
|
||||
case LIR_fge: cc = LT; break;
|
||||
}
|
||||
} else {
|
||||
switch (condop) {
|
||||
case LIR_feq: cc = EQ; break;
|
||||
case LIR_flt: cc = MI; break;
|
||||
case LIR_fgt: cc = GT; break;
|
||||
case LIR_fle: cc = LS; break;
|
||||
case LIR_fge: cc = GE; break;
|
||||
}
|
||||
}
|
||||
|
||||
B_cond(cc, targ);
|
||||
asm_output("b(%d) 0x%08x", cc, (unsigned int) targ);
|
||||
|
||||
NIns *at = _nIns;
|
||||
asm_fcmp(cond);
|
||||
|
@ -1240,7 +1208,14 @@ Assembler::asm_fcond(LInsp ins)
|
|||
// only want certain regs
|
||||
Register r = prepResultReg(ins, AllowableFlagRegs);
|
||||
|
||||
SETE(r);
|
||||
switch (ins->opcode()) {
|
||||
case LIR_feq: SET(r,EQ,NE); break;
|
||||
case LIR_flt: SET(r,MI,PL); break;
|
||||
case LIR_fgt: SET(r,GT,LE); break;
|
||||
case LIR_fle: SET(r,LS,HI); break;
|
||||
case LIR_fge: SET(r,GE,LT); break;
|
||||
}
|
||||
|
||||
asm_fcmp(ins);
|
||||
}
|
||||
|
||||
|
|
|
@ -156,6 +156,7 @@ typedef enum {
|
|||
NV = 0xF // NeVer
|
||||
} ConditionCode;
|
||||
|
||||
const char *ccName(ConditionCode cc);
|
||||
|
||||
typedef int RegisterMask;
|
||||
typedef struct _FragInfo {
|
||||
|
@ -692,23 +693,26 @@ typedef enum {
|
|||
|
||||
// MOV(EQ) _r, #1
|
||||
// EOR(NE) _r, _r
|
||||
#define SET(_r,_cond,_opp) \
|
||||
#define SET(_r,_cond,_opp) do { \
|
||||
underrunProtect(8); \
|
||||
*(--_nIns) = (NIns)( (_opp<<28) | (1<<21) | ((_r)<<16) | ((_r)<<12) | (_r) ); \
|
||||
*(--_nIns) = (NIns)( (_cond<<28) | (0x3A<<20) | ((_r)<<12) | (1) );
|
||||
*(--_nIns) = (NIns)( (_cond<<28) | (0x3A<<20) | ((_r)<<12) | (1) ); \
|
||||
asm_output("mov%s %s, #1", ccName(_cond), gpn(r), gpn(r)); \
|
||||
asm_output("eor%s %s, %s", ccName(_opp), gpn(r), gpn(r)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define SETE(r) do {SET(r,EQ,NE); asm_output("sete %s",gpn(r)); } while(0)
|
||||
#define SETL(r) do {SET(r,LT,GE); asm_output("setl %s",gpn(r)); } while(0)
|
||||
#define SETLE(r) do {SET(r,LE,GT); asm_output("setle %s",gpn(r)); } while(0)
|
||||
#define SETG(r) do {SET(r,GT,LE); asm_output("setg %s",gpn(r)); } while(0)
|
||||
#define SETGE(r) do {SET(r,GE,LT); asm_output("setge %s",gpn(r)); } while(0)
|
||||
#define SETB(r) do {SET(r,CC,CS); asm_output("setb %s",gpn(r)); } while(0)
|
||||
#define SETBE(r) do {SET(r,LS,HI); asm_output("setb %s",gpn(r)); } while(0)
|
||||
#define SETAE(r) do {SET(r,CS,CC); asm_output("setae %s",gpn(r)); } while(0)
|
||||
#define SETA(r) do {SET(r,HI,LS); asm_output("seta %s",gpn(r)); } while(0)
|
||||
#define SETO(r) do {SET(r,VS,LS); asm_output("seto %s",gpn(r)); } while(0)
|
||||
#define SETC(r) do {SET(r,CS,LS); asm_output("setc %s",gpn(r)); } while(0)
|
||||
#define SETE(r) SET(r,EQ,NE)
|
||||
#define SETL(r) SET(r,LT,GE)
|
||||
#define SETLE(r) SET(r,LE,GT)
|
||||
#define SETG(r) SET(r,GT,LE)
|
||||
#define SETGE(r) SET(r,GE,LT)
|
||||
#define SETB(r) SET(r,CC,CS)
|
||||
#define SETBE(r) SET(r,LS,HI)
|
||||
#define SETAE(r) SET(r,CS,CC)
|
||||
#define SETA(r) SET(r,HI,LS)
|
||||
#define SETO(r) SET(r,VS,LS)
|
||||
#define SETC(r) SET(r,CS,LS)
|
||||
|
||||
// This zero-extends a reg that has been set using one of the SET macros,
|
||||
// but is a NOOP on ARM/Thumb
|
||||
|
|
Загрузка…
Ссылка в новой задаче