[arm] fix up ARM floating point comparisons; fixes ARM trace-test (relanding)

This commit is contained in:
Vladimir Vukicevic 2009-01-23 00:53:15 -08:00
Родитель 937e5d9cec
Коммит 56155f4e54
2 изменённых файлов: 54 добавлений и 75 удалений

Просмотреть файл

@ -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