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() {
return false; // TODO
}
}
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(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 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 StackAlignmentInBytes = 8;
@ -570,10 +581,37 @@ using namespace isa;
// shortcut functions
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 void freeTemp(Context* con, int r) { con->client->releaseTemporary(r); }
inline int64_t getValue(Assembler::Constant* c) { return c->value->value(); }
inline int newTemp(Context* con) {
return con->client->acquireTemporary();
}
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
write4(uint8_t* dst, uint32_t v)
@ -879,46 +917,59 @@ swapRR(Context* c, unsigned aSize, Assembler::Register* a,
}
void
moveRR(Context* c, unsigned srcSize, Assembler::Register* src,
moveRR(Context* con, unsigned srcSize, Assembler::Register* src,
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) {
case 1:
emit(c, lsli(dst->low, src->low, 24));
emit(c, asri(dst->low, dst->low, 24));
emit(con, lsli(dst->low, src->low, 24));
emit(con, asri(dst->low, dst->low, 24));
break;
case 2:
emit(c, lsli(dst->low, src->low, 16));
emit(c, asri(dst->low, dst->low, 16));
emit(con, lsli(dst->low, src->low, 16));
emit(con, asri(dst->low, dst->low, 16));
break;
case 4:
case 8:
if (srcSize == 4 and dstSize == 8) {
moveRR(c, 4, src, 4, dst);
emit(c, asri(dst->high, src->low, 31));
moveRR(con, 4, src, 4, dst);
emit(con, asri(dst->high, src->low, 31));
} else if (srcSize == 8 and dstSize == 8) {
Assembler::Register srcHigh(src->high);
Assembler::Register dstHigh(dst->high);
if (src->high == dst->low) {
if (src->low == dst->high) {
swapRR(c, 4, src, 4, dst);
swapRR(con, 4, src, 4, dst);
} else {
moveRR(c, 4, &srcHigh, 4, &dstHigh);
moveRR(c, 4, src, 4, dst);
moveRR(con, 4, &srcHigh, 4, &dstHigh);
moveRR(con, 4, src, 4, dst);
}
} else {
moveRR(c, 4, src, 4, dst);
moveRR(c, 4, &srcHigh, 4, &dstHigh);
moveRR(con, 4, src, 4, dst);
moveRR(con, 4, &srcHigh, 4, &dstHigh);
}
} else if (src->low != dst->low) {
emit(c, mov(dst->low, src->low));
emit(con, mov(dst->low, src->low));
}
break;
default: abort(c);
default: abort(con);
}
}
@ -937,26 +988,32 @@ moveZRR(Context* c, unsigned srcSize, Assembler::Register* src,
}
void
moveCR2(Context* c, unsigned, Assembler::Constant* src,
unsigned dstSize, Assembler::Register* dst, Promise* callOffset)
moveCR2(Context* con, unsigned size, Assembler::Constant* src,
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)) {
emit(c, movi(dst->low, lo8(getValue(src))));
emit(con, movi(dst->low, lo8(getValue(src))));
} else {
appendConstantPoolEntry(c, src->value, callOffset);
emit(c, ldri(dst->low, ProgramCounter, 0));
appendConstantPoolEntry(con, src->value, callOffset);
emit(con, ldri(dst->low, ProgramCounter, 0));
}
} else {
abort(c); // todo
abort(con); // todo
}
}
void
moveCR(Context* c, unsigned srcSize, Assembler::Constant* src,
unsigned dstSize, Assembler::Register* dst)
moveCR(Context* con, unsigned size, Assembler::Constant* src,
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) {
@ -1096,7 +1153,8 @@ void floatAddR(Context* con, unsigned size, Assembler::Register* a, Assembler::R
if (size == 8) {
emit(con, faddd(t->low, a->low, b->low));
} 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
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)
{
if (index != NoRegister) {
bool release;
int normalized = normalize
(c, offset, index, scale, &preserveIndex, &release);
(con, offset, index, scale, &preserveIndex, &release);
switch (size) {
case 1:
emit(c, strb(src->low, base, normalized));
break;
if (isFpr(src)) { // floating-point store
if (size == 4) {
/**/fprintf(stderr, ">>>>>>>>>>>>>>>>>>>>>>>> fpr store base-indexed\n");
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:
emit(c, strh(src->low, base, normalized));
break;
case 2:
emit(con, strh(src->low, base, normalized));
break;
case 4:
emit(c, str(src->low, base, normalized));
break;
case 4:
emit(con, str(src->low, base, normalized));
break;
case 8: {
Assembler::Register srcHigh(src->high);
store(c, 4, &srcHigh, base, 0, normalized, 1, preserveIndex);
store(c, 4, src, base, 4, normalized, 1, preserveIndex);
} break;
case 8: {
Assembler::Register srcHigh(src->high);
store(con, 4, &srcHigh, base, 0, normalized, 1, preserveIndex);
store(con, 4, src, base, 4, normalized, 1, preserveIndex);
} break;
default: abort(c);
default: abort(con);
}
}
if (release) c->client->releaseTemporary(normalized);
if (release) con->client->releaseTemporary(normalized);
} else if (size == 8
or abs(offset) == (abs(offset) & 0xFF)
or (size != 2 and abs(offset) == (abs(offset) & 0xFFF)))
{
switch (size) {
case 1:
emit(c, strbi(src->low, base, offset));
break;
if (isFpr(src)) {
/**/fprintf(stderr, ">>>>>>>>>>>>>>>>>>>>>>>> fpr store offset -> %d\n", src->low);
if (size == 4) emit(con, fsts(toFpr(src), base, offset));
else abort(con);
} else {
switch (size) {
case 1:
emit(con, strbi(src->low, base, offset));
break;
case 2:
emit(c, strhi(src->low, base, offset));
break;
case 2:
emit(con, strhi(src->low, base, offset));
break;
case 4:
emit(c, stri(src->low, base, offset));
break;
case 4:
emit(con, stri(src->low, base, offset));
break;
case 8: {
Assembler::Register srcHigh(src->high);
store(c, 4, &srcHigh, base, offset, NoRegister, 1, false);
store(c, 4, src, base, offset + 4, NoRegister, 1, false);
} break;
case 8: {
Assembler::Register srcHigh(src->high);
store(con, 4, &srcHigh, base, offset, NoRegister, 1, false);
store(con, 4, src, base, offset + 4, NoRegister, 1, false);
} break;
default: abort(c);
default: abort(con);
}
}
} else {
Assembler::Register tmp(c->client->acquireTemporary());
Assembler::Register tmp(con->client->acquireTemporary());
ResolvedPromise offsetPromise(offset);
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
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,
bool preserveIndex, bool signExtend)
{
if (index != NoRegister) {
bool release;
int normalized = normalize
(c, offset, index, scale, &preserveIndex, &release);
(con, offset, index, scale, &preserveIndex, &release);
switch (srcSize) {
case 1:
if (signExtend) {
emit(c, ldrsb(dst->low, base, normalized));
} else {
emit(c, ldrb(dst->low, base, normalized));
if (isFpr(dst)) { // floating-point store
if (srcSize == 4) {
/**/fprintf(stderr, ">>>>>>>>>>>>>>>>>>>>>>>> fpr load base-indexed\n");
Assembler::Register base_(base),
normalized_(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:
if (signExtend) {
emit(c, ldrsh(dst->low, base, normalized));
} else {
emit(c, ldrh(dst->low, base, normalized));
case 2:
if (signExtend) {
emit(con, ldrsh(dst->low, base, normalized));
} else {
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)
or abs(offset) == (abs(offset) & 0xFF)
or (srcSize != 2
and (srcSize != 1 or not signExtend)
and abs(offset) == (abs(offset) & 0xFFF)))
{
switch (srcSize) {
case 1:
if (signExtend) {
emit(c, ldrsbi(dst->low, base, offset));
} else {
emit(c, ldrbi(dst->low, base, offset));
if (isFpr(dst)) {
/**/fprintf(stderr, ">>>>>>>>>>>>>>>>>>>>>>>> fpr load offset <- %d\n", dst->low);
if (srcSize == 4) emit(con, flds(toFpr(dst), base, offset));
else abort(con);
} else {
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 {
Assembler::Register tmp(c->client->acquireTemporary());
Assembler::Register tmp(con->client->acquireTemporary());
ResolvedPromise offsetPromise(offset);
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);
Assembler::Register tmp(4);
moveCR2(c, TargetBytesPerWord, target, TargetBytesPerWord, &tmp, offset(c));
moveCR2(c, TargetBytesPerWord, target, &tmp, offset(c));
callR(c, TargetBytesPerWord, &tmp);
}
@ -1783,7 +1887,7 @@ longJumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target)
assert(c, size == TargetBytesPerWord);
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);
}
@ -1970,7 +2074,7 @@ class MyArchitecture: public Assembler::Architecture {
}
virtual unsigned floatRegisterSize() {
return vfpSupported() ? 16 : 0;
return vfpSupported() ? 4 : 0;
}
virtual uint32_t generalRegisterMask() {
@ -2197,19 +2301,31 @@ class MyArchitecture: public Assembler::Architecture {
case FloatSquareRoot:
case FloatNegate:
case Float2Float:
if (!vfpSupported()) {
if (vfpSupported()) {
*aTypeMask = (1 << RegisterOperand);
*aRegisterMask = FPR_MASK;
*thunk = true;
} else {
*thunk = true;
}
break;
case Float2Int:
if (!vfpSupported() || bSize != 4) {
if (vfpSupported() && bSize == 4 && aSize == 4) {
*aTypeMask = (1 << RegisterOperand);
*aRegisterMask = FPR_MASK;
*thunk = true;
} else {
*thunk = true;
}
break;
case Int2Float:
if (!vfpSupported() || aSize != 4) {
if (vfpSupported() && aSize == 4 && bSize == 4) {
*aTypeMask = (1 << RegisterOperand);
*aRegisterMask = FPR_MASK;
*thunk = true;
} else {
*thunk = true;
}
break;
@ -2287,6 +2403,9 @@ class MyArchitecture: public Assembler::Architecture {
case Divide:
case Remainder:
*thunk = true;
break;
case FloatAdd:
case FloatSubtract:
case FloatMultiply:
@ -2302,9 +2421,8 @@ class MyArchitecture: public Assembler::Architecture {
case JumpIfFloatGreaterOrUnordered:
case JumpIfFloatLessOrEqualOrUnordered:
case JumpIfFloatGreaterOrEqualOrUnordered:
if (!vfpSupported()) {
*thunk = true;
}
if (vfpSupported()) *thunk = true;
else *thunk = true;
break;
default: