Additional floating-point support code; passing all tests when vfpSupport() returns false.

This commit is contained in:
JET
2012-01-26 18:26:29 -07:00
parent 233725e232
commit 47b91f38ee

View File

@ -234,6 +234,7 @@ inline int bhs(int offset) { return SETCOND(b(offset), CS); }
bool vfpSupported() { bool vfpSupported() {
return false; // TODO return false; // TODO
} }
} }
const uint64_t MASK_LO32 = 0xffffffff; const uint64_t MASK_LO32 = 0xffffffff;
@ -262,9 +263,19 @@ inline int carry16(target_intptr_t v) { return static_cast<int16_t>(v) < 0 ? 1 :
inline bool isOfWidth(int64_t i, int size) { return static_cast<uint64_t>(i) >> size == 0; } inline bool isOfWidth(int64_t i, int size) { return static_cast<uint64_t>(i) >> size == 0; }
inline bool isOfWidth(int i, int size) { return static_cast<unsigned>(i) >> size == 0; } inline bool isOfWidth(int i, int size) { return static_cast<unsigned>(i) >> size == 0; }
const int N_GPRS = 16;
const int N_FPRS = 16;
const uint32_t GPR_MASK = 0xffff; const uint32_t GPR_MASK = 0xffff;
const uint32_t FPR_MASK = 0xffff0000; const uint32_t FPR_MASK = 0xffff0000;
inline bool isFpr(Assembler::Register* reg) {
return reg->low >= N_GPRS;
}
inline int toFpr(Assembler::Register* reg) {
return reg->low - N_GPRS;
}
const unsigned FrameHeaderSize = 1; const unsigned FrameHeaderSize = 1;
const unsigned StackAlignmentInBytes = 8; const unsigned StackAlignmentInBytes = 8;
@ -570,10 +581,37 @@ using namespace isa;
// shortcut functions // shortcut functions
inline void emit(Context* con, int code) { con->code.append4(code); } inline void emit(Context* con, int code) { con->code.append4(code); }
inline int newTemp(Context* con) { return con->client->acquireTemporary(); }
inline int newTemp(Context* con, unsigned mask) { return con->client->acquireTemporary(mask); } inline int newTemp(Context* con) {
inline void freeTemp(Context* con, int r) { con->client->releaseTemporary(r); } return con->client->acquireTemporary();
inline int64_t getValue(Assembler::Constant* c) { return c->value->value(); } }
inline int newTemp(Context* con, unsigned mask) {
return con->client->acquireTemporary(mask);
}
inline void freeTemp(Context* con, int r) {
con->client->releaseTemporary(r);
}
inline int64_t getValue(Assembler::Constant* c) {
return c->value->value();
}
inline Assembler::Register makeTemp(Context* con) {
Assembler::Register tmp(newTemp(con));
return tmp;
}
inline Assembler::Register makeTemp64(Context* con) {
Assembler::Register tmp(newTemp(con), newTemp(con));
return tmp;
}
inline void freeTemp(Context* con, const Assembler::Register& tmp) {
if (tmp.low != NoRegister) freeTemp(con, tmp.low);
if (tmp.high != NoRegister) freeTemp(con, tmp.high);
}
inline void inline void
write4(uint8_t* dst, uint32_t v) write4(uint8_t* dst, uint32_t v)
@ -879,46 +917,59 @@ swapRR(Context* c, unsigned aSize, Assembler::Register* a,
} }
void void
moveRR(Context* c, unsigned srcSize, Assembler::Register* src, moveRR(Context* con, unsigned srcSize, Assembler::Register* src,
unsigned dstSize, Assembler::Register* dst) unsigned dstSize, Assembler::Register* dst)
{ {
bool srcIsFpr = isFpr(src);
bool dstIsFpr = isFpr(dst);
if (srcIsFpr || dstIsFpr) { // floating-point register(s) involved
/**/fprintf(stderr, ">>>>>>>>>>>>>>>>>>>>>>>> %d <- %d\n", dst->low, src->low);
// FPR to FPR
if (srcIsFpr && dstIsFpr) emit(con, fcpys(toFpr(dst), toFpr(src)));
// FPR to GPR
else if (srcIsFpr) emit(con, fmrs(dst->low, toFpr(src)));
// GPR to FPR
else emit(con, fmsr(toFpr(dst), src->low));
return;
}
switch (srcSize) { switch (srcSize) {
case 1: case 1:
emit(c, lsli(dst->low, src->low, 24)); emit(con, lsli(dst->low, src->low, 24));
emit(c, asri(dst->low, dst->low, 24)); emit(con, asri(dst->low, dst->low, 24));
break; break;
case 2: case 2:
emit(c, lsli(dst->low, src->low, 16)); emit(con, lsli(dst->low, src->low, 16));
emit(c, asri(dst->low, dst->low, 16)); emit(con, asri(dst->low, dst->low, 16));
break; break;
case 4: case 4:
case 8: case 8:
if (srcSize == 4 and dstSize == 8) { if (srcSize == 4 and dstSize == 8) {
moveRR(c, 4, src, 4, dst); moveRR(con, 4, src, 4, dst);
emit(c, asri(dst->high, src->low, 31)); emit(con, asri(dst->high, src->low, 31));
} else if (srcSize == 8 and dstSize == 8) { } else if (srcSize == 8 and dstSize == 8) {
Assembler::Register srcHigh(src->high); Assembler::Register srcHigh(src->high);
Assembler::Register dstHigh(dst->high); Assembler::Register dstHigh(dst->high);
if (src->high == dst->low) { if (src->high == dst->low) {
if (src->low == dst->high) { if (src->low == dst->high) {
swapRR(c, 4, src, 4, dst); swapRR(con, 4, src, 4, dst);
} else { } else {
moveRR(c, 4, &srcHigh, 4, &dstHigh); moveRR(con, 4, &srcHigh, 4, &dstHigh);
moveRR(c, 4, src, 4, dst); moveRR(con, 4, src, 4, dst);
} }
} else { } else {
moveRR(c, 4, src, 4, dst); moveRR(con, 4, src, 4, dst);
moveRR(c, 4, &srcHigh, 4, &dstHigh); moveRR(con, 4, &srcHigh, 4, &dstHigh);
} }
} else if (src->low != dst->low) { } else if (src->low != dst->low) {
emit(c, mov(dst->low, src->low)); emit(con, mov(dst->low, src->low));
} }
break; break;
default: abort(c); default: abort(con);
} }
} }
@ -937,26 +988,32 @@ moveZRR(Context* c, unsigned srcSize, Assembler::Register* src,
} }
void void
moveCR2(Context* c, unsigned, Assembler::Constant* src, moveCR2(Context* con, unsigned size, Assembler::Constant* src,
unsigned dstSize, Assembler::Register* dst, Promise* callOffset) Assembler::Register* dst, Promise* callOffset)
{ {
if (dstSize <= 4) { if (isFpr(dst)) { // floating-point
Assembler::Register tmp = makeTemp(con);
/**/fprintf(stderr, ">>>>>>>>>>>>>>>>>>>>>>>> %d <- 0x%llx\n", tmp.low, getValue(src));
moveCR2(con, size, src, &tmp, 0);
moveRR(con, size, &tmp, size, dst);
freeTemp(con, tmp);
} else if (size <= 4) {
if (src->value->resolved() and isOfWidth(getValue(src), 8)) { if (src->value->resolved() and isOfWidth(getValue(src), 8)) {
emit(c, movi(dst->low, lo8(getValue(src)))); emit(con, movi(dst->low, lo8(getValue(src))));
} else { } else {
appendConstantPoolEntry(c, src->value, callOffset); appendConstantPoolEntry(con, src->value, callOffset);
emit(c, ldri(dst->low, ProgramCounter, 0)); emit(con, ldri(dst->low, ProgramCounter, 0));
} }
} else { } else {
abort(c); // todo abort(con); // todo
} }
} }
void void
moveCR(Context* c, unsigned srcSize, Assembler::Constant* src, moveCR(Context* con, unsigned size, Assembler::Constant* src,
unsigned dstSize, Assembler::Register* dst) unsigned, Assembler::Register* dst)
{ {
moveCR2(c, srcSize, src, dstSize, dst, 0); moveCR2(con, size, src, dst, 0);
} }
void addR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { void addR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) {
@ -1096,7 +1153,8 @@ void floatAddR(Context* con, unsigned size, Assembler::Register* a, Assembler::R
if (size == 8) { if (size == 8) {
emit(con, faddd(t->low, a->low, b->low)); emit(con, faddd(t->low, a->low, b->low));
} else { } else {
emit(con, fadds(t->low, a->low, b->low)); fprintf(stderr, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ %d <- %d + %d\n", toFpr(t), toFpr(a), toFpr(b));
emit(con, fadds(toFpr(t), toFpr(a), toFpr(b)));
} }
} }
@ -1175,71 +1233,91 @@ normalize(Context* c, int offset, int index, unsigned scale,
} }
void void
store(Context* c, unsigned size, Assembler::Register* src, store(Context* con, unsigned size, Assembler::Register* src,
int base, int offset, int index, unsigned scale, bool preserveIndex) int base, int offset, int index, unsigned scale, bool preserveIndex)
{ {
if (index != NoRegister) { if (index != NoRegister) {
bool release; bool release;
int normalized = normalize int normalized = normalize
(c, offset, index, scale, &preserveIndex, &release); (con, offset, index, scale, &preserveIndex, &release);
switch (size) { if (isFpr(src)) { // floating-point store
case 1: if (size == 4) {
emit(c, strb(src->low, base, normalized)); /**/fprintf(stderr, ">>>>>>>>>>>>>>>>>>>>>>>> fpr store base-indexed\n");
break; Assembler::Register base_(base),
normalized_(normalized),
absAddr = makeTemp(con);
addR(con, size, &base_, &normalized_, &absAddr);
emit(con, fsts(toFpr(src), absAddr.low));
freeTemp(con, absAddr);
}
else abort(con);
} else {
switch (size) {
case 1:
emit(con, strb(src->low, base, normalized));
break;
case 2: case 2:
emit(c, strh(src->low, base, normalized)); emit(con, strh(src->low, base, normalized));
break; break;
case 4: case 4:
emit(c, str(src->low, base, normalized)); emit(con, str(src->low, base, normalized));
break; break;
case 8: { case 8: {
Assembler::Register srcHigh(src->high); Assembler::Register srcHigh(src->high);
store(c, 4, &srcHigh, base, 0, normalized, 1, preserveIndex); store(con, 4, &srcHigh, base, 0, normalized, 1, preserveIndex);
store(c, 4, src, base, 4, normalized, 1, preserveIndex); store(con, 4, src, base, 4, normalized, 1, preserveIndex);
} break; } break;
default: abort(c); default: abort(con);
}
} }
if (release) c->client->releaseTemporary(normalized); if (release) con->client->releaseTemporary(normalized);
} else if (size == 8 } else if (size == 8
or abs(offset) == (abs(offset) & 0xFF) or abs(offset) == (abs(offset) & 0xFF)
or (size != 2 and abs(offset) == (abs(offset) & 0xFFF))) or (size != 2 and abs(offset) == (abs(offset) & 0xFFF)))
{ {
switch (size) { if (isFpr(src)) {
case 1: /**/fprintf(stderr, ">>>>>>>>>>>>>>>>>>>>>>>> fpr store offset -> %d\n", src->low);
emit(c, strbi(src->low, base, offset)); if (size == 4) emit(con, fsts(toFpr(src), base, offset));
break; else abort(con);
} else {
switch (size) {
case 1:
emit(con, strbi(src->low, base, offset));
break;
case 2: case 2:
emit(c, strhi(src->low, base, offset)); emit(con, strhi(src->low, base, offset));
break; break;
case 4: case 4:
emit(c, stri(src->low, base, offset)); emit(con, stri(src->low, base, offset));
break; break;
case 8: { case 8: {
Assembler::Register srcHigh(src->high); Assembler::Register srcHigh(src->high);
store(c, 4, &srcHigh, base, offset, NoRegister, 1, false); store(con, 4, &srcHigh, base, offset, NoRegister, 1, false);
store(c, 4, src, base, offset + 4, NoRegister, 1, false); store(con, 4, src, base, offset + 4, NoRegister, 1, false);
} break; } break;
default: abort(c); default: abort(con);
}
} }
} else { } else {
Assembler::Register tmp(c->client->acquireTemporary()); Assembler::Register tmp(con->client->acquireTemporary());
ResolvedPromise offsetPromise(offset); ResolvedPromise offsetPromise(offset);
Assembler::Constant offsetConstant(&offsetPromise); Assembler::Constant offsetConstant(&offsetPromise);
moveCR(c, TargetBytesPerWord, &offsetConstant, TargetBytesPerWord, &tmp); moveCR(con, TargetBytesPerWord, &offsetConstant,
TargetBytesPerWord, &tmp);
store(c, size, src, base, 0, tmp.low, 1, false); store(con, size, src, base, 0, tmp.low, 1, false);
c->client->releaseTemporary(tmp.low); con->client->releaseTemporary(tmp.low);
} }
} }
@ -1270,98 +1348,124 @@ moveAndUpdateRM(Context* c, unsigned srcSize UNUSED, Assembler::Register* src,
} }
void void
load(Context* c, unsigned srcSize, int base, int offset, int index, load(Context* con, unsigned srcSize, int base, int offset, int index,
unsigned scale, unsigned dstSize, Assembler::Register* dst, unsigned scale, unsigned dstSize, Assembler::Register* dst,
bool preserveIndex, bool signExtend) bool preserveIndex, bool signExtend)
{ {
if (index != NoRegister) { if (index != NoRegister) {
bool release; bool release;
int normalized = normalize int normalized = normalize
(c, offset, index, scale, &preserveIndex, &release); (con, offset, index, scale, &preserveIndex, &release);
switch (srcSize) { if (isFpr(dst)) { // floating-point store
case 1: if (srcSize == 4) {
if (signExtend) { /**/fprintf(stderr, ">>>>>>>>>>>>>>>>>>>>>>>> fpr load base-indexed\n");
emit(c, ldrsb(dst->low, base, normalized)); Assembler::Register base_(base),
} else { normalized_(normalized),
emit(c, ldrb(dst->low, base, normalized)); absAddr = makeTemp(con);
addR(con, srcSize, &base_, &normalized_, &absAddr);
emit(con, flds(toFpr(dst), absAddr.low));
freeTemp(con, absAddr);
} }
break; else abort(con);
} else {
switch (srcSize) {
case 1:
if (signExtend) {
emit(con, ldrsb(dst->low, base, normalized));
} else {
emit(con, ldrb(dst->low, base, normalized));
}
break;
case 2: case 2:
if (signExtend) { if (signExtend) {
emit(c, ldrsh(dst->low, base, normalized)); emit(con, ldrsh(dst->low, base, normalized));
} else { } else {
emit(c, ldrh(dst->low, base, normalized)); emit(con, ldrh(dst->low, base, normalized));
}
break;
case 4:
case 8: {
if (srcSize == 4 and dstSize == 8) {
load(con, 4, base, 0, normalized, 1, 4, dst, preserveIndex,
false);
moveRR(con, 4, dst, 8, dst);
} else if (srcSize == 8 and dstSize == 8) {
Assembler::Register dstHigh(dst->high);
load(con, 4, base, 0, normalized, 1, 4, &dstHigh,
preserveIndex, false);
load(con, 4, base, 4, normalized, 1, 4, dst, preserveIndex,
false);
} else {
emit(con, ldr(dst->low, base, normalized));
}
} break;
default: abort(con);
} }
break;
case 4:
case 8: {
if (srcSize == 4 and dstSize == 8) {
load(c, 4, base, 0, normalized, 1, 4, dst, preserveIndex, false);
moveRR(c, 4, dst, 8, dst);
} else if (srcSize == 8 and dstSize == 8) {
Assembler::Register dstHigh(dst->high);
load(c, 4, base, 0, normalized, 1, 4, &dstHigh, preserveIndex, false);
load(c, 4, base, 4, normalized, 1, 4, dst, preserveIndex, false);
} else {
emit(c, ldr(dst->low, base, normalized));
}
} break;
default: abort(c);
} }
if (release) c->client->releaseTemporary(normalized); if (release) con->client->releaseTemporary(normalized);
} else if ((srcSize == 8 and dstSize == 8) } else if ((srcSize == 8 and dstSize == 8)
or abs(offset) == (abs(offset) & 0xFF) or abs(offset) == (abs(offset) & 0xFF)
or (srcSize != 2 or (srcSize != 2
and (srcSize != 1 or not signExtend) and (srcSize != 1 or not signExtend)
and abs(offset) == (abs(offset) & 0xFFF))) and abs(offset) == (abs(offset) & 0xFFF)))
{ {
switch (srcSize) { if (isFpr(dst)) {
case 1: /**/fprintf(stderr, ">>>>>>>>>>>>>>>>>>>>>>>> fpr load offset <- %d\n", dst->low);
if (signExtend) { if (srcSize == 4) emit(con, flds(toFpr(dst), base, offset));
emit(c, ldrsbi(dst->low, base, offset)); else abort(con);
} else { } else {
emit(c, ldrbi(dst->low, base, offset)); switch (srcSize) {
case 1:
if (signExtend) {
emit(con, ldrsbi(dst->low, base, offset));
} else {
emit(con, ldrbi(dst->low, base, offset));
}
break;
case 2:
if (signExtend) {
emit(con, ldrshi(dst->low, base, offset));
} else {
emit(con, ldrhi(dst->low, base, offset));
}
break;
case 4:
emit(con, ldri(dst->low, base, offset));
break;
case 8: {
if (dstSize == 8) {
Assembler::Register dstHigh(dst->high);
load(con, 4, base, offset, NoRegister, 1, 4, &dstHigh, false,
false);
load(con, 4, base, offset + 4, NoRegister, 1, 4, dst, false,
false);
} else {
emit(con, ldri(dst->low, base, offset));
}
} break;
default: abort(con);
} }
break;
case 2:
if (signExtend) {
emit(c, ldrshi(dst->low, base, offset));
} else {
emit(c, ldrhi(dst->low, base, offset));
}
break;
case 4:
emit(c, ldri(dst->low, base, offset));
break;
case 8: {
if (dstSize == 8) {
Assembler::Register dstHigh(dst->high);
load(c, 4, base, offset, NoRegister, 1, 4, &dstHigh, false, false);
load(c, 4, base, offset + 4, NoRegister, 1, 4, dst, false, false);
} else {
emit(c, ldri(dst->low, base, offset));
}
} break;
default: abort(c);
} }
} else { } else {
Assembler::Register tmp(c->client->acquireTemporary()); Assembler::Register tmp(con->client->acquireTemporary());
ResolvedPromise offsetPromise(offset); ResolvedPromise offsetPromise(offset);
Assembler::Constant offsetConstant(&offsetPromise); Assembler::Constant offsetConstant(&offsetPromise);
moveCR(c, TargetBytesPerWord, &offsetConstant, TargetBytesPerWord, &tmp); moveCR(con, TargetBytesPerWord, &offsetConstant, TargetBytesPerWord,
&tmp);
load(c, srcSize, base, 0, tmp.low, 1, dstSize, dst, false, signExtend); load(con, srcSize, base, 0, tmp.low, 1, dstSize, dst, false,
signExtend);
c->client->releaseTemporary(tmp.low); con->client->releaseTemporary(tmp.low);
} }
} }
@ -1773,7 +1877,7 @@ longCallC(Context* c, unsigned size UNUSED, Assembler::Constant* target)
assert(c, size == TargetBytesPerWord); assert(c, size == TargetBytesPerWord);
Assembler::Register tmp(4); Assembler::Register tmp(4);
moveCR2(c, TargetBytesPerWord, target, TargetBytesPerWord, &tmp, offset(c)); moveCR2(c, TargetBytesPerWord, target, &tmp, offset(c));
callR(c, TargetBytesPerWord, &tmp); callR(c, TargetBytesPerWord, &tmp);
} }
@ -1783,7 +1887,7 @@ longJumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target)
assert(c, size == TargetBytesPerWord); assert(c, size == TargetBytesPerWord);
Assembler::Register tmp(4); // a non-arg reg that we don't mind clobbering Assembler::Register tmp(4); // a non-arg reg that we don't mind clobbering
moveCR2(c, TargetBytesPerWord, target, TargetBytesPerWord, &tmp, offset(c)); moveCR2(c, TargetBytesPerWord, target, &tmp, offset(c));
jumpR(c, TargetBytesPerWord, &tmp); jumpR(c, TargetBytesPerWord, &tmp);
} }
@ -1970,7 +2074,7 @@ class MyArchitecture: public Assembler::Architecture {
} }
virtual unsigned floatRegisterSize() { virtual unsigned floatRegisterSize() {
return vfpSupported() ? 16 : 0; return vfpSupported() ? 4 : 0;
} }
virtual uint32_t generalRegisterMask() { virtual uint32_t generalRegisterMask() {
@ -2197,19 +2301,31 @@ class MyArchitecture: public Assembler::Architecture {
case FloatSquareRoot: case FloatSquareRoot:
case FloatNegate: case FloatNegate:
case Float2Float: case Float2Float:
if (!vfpSupported()) { if (vfpSupported()) {
*aTypeMask = (1 << RegisterOperand);
*aRegisterMask = FPR_MASK;
*thunk = true;
} else {
*thunk = true; *thunk = true;
} }
break; break;
case Float2Int: case Float2Int:
if (!vfpSupported() || bSize != 4) { if (vfpSupported() && bSize == 4 && aSize == 4) {
*aTypeMask = (1 << RegisterOperand);
*aRegisterMask = FPR_MASK;
*thunk = true;
} else {
*thunk = true; *thunk = true;
} }
break; break;
case Int2Float: case Int2Float:
if (!vfpSupported() || aSize != 4) { if (vfpSupported() && aSize == 4 && bSize == 4) {
*aTypeMask = (1 << RegisterOperand);
*aRegisterMask = FPR_MASK;
*thunk = true;
} else {
*thunk = true; *thunk = true;
} }
break; break;
@ -2287,6 +2403,9 @@ class MyArchitecture: public Assembler::Architecture {
case Divide: case Divide:
case Remainder: case Remainder:
*thunk = true;
break;
case FloatAdd: case FloatAdd:
case FloatSubtract: case FloatSubtract:
case FloatMultiply: case FloatMultiply:
@ -2302,9 +2421,8 @@ class MyArchitecture: public Assembler::Architecture {
case JumpIfFloatGreaterOrUnordered: case JumpIfFloatGreaterOrUnordered:
case JumpIfFloatLessOrEqualOrUnordered: case JumpIfFloatLessOrEqualOrUnordered:
case JumpIfFloatGreaterOrEqualOrUnordered: case JumpIfFloatGreaterOrEqualOrUnordered:
if (!vfpSupported()) { if (vfpSupported()) *thunk = true;
*thunk = true; else *thunk = true;
}
break; break;
default: default: