mirror of
https://github.com/corda/corda.git
synced 2025-01-07 13:38:47 +00:00
add lcmp instruction to Compiler and corresponding LongCompare instruction to Assembler, since that's the only efficient way to implement the lcmp bytecode on x86
This commit is contained in:
parent
357acbdb0f
commit
eabb37e6eb
@ -37,6 +37,7 @@ enum BinaryOperation {
|
|||||||
MoveZ,
|
MoveZ,
|
||||||
Move4To8,
|
Move4To8,
|
||||||
Swap,
|
Swap,
|
||||||
|
LongCompare,
|
||||||
Compare,
|
Compare,
|
||||||
Add,
|
Add,
|
||||||
Subtract,
|
Subtract,
|
||||||
|
@ -2836,38 +2836,10 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case lcmp: {
|
case lcmp: {
|
||||||
Compiler::Operand* next = c->label();
|
|
||||||
Compiler::Operand* less = c->label();
|
|
||||||
Compiler::Operand* greater = c->label();
|
|
||||||
|
|
||||||
Compiler::Operand* a = frame->popLong();
|
Compiler::Operand* a = frame->popLong();
|
||||||
Compiler::Operand* b = frame->popLong();
|
Compiler::Operand* b = frame->popLong();
|
||||||
|
|
||||||
c->cmp(8, a, b);
|
frame->pushInt(c->load(4, c->lcmp(a, b)));
|
||||||
|
|
||||||
c->jl(less);
|
|
||||||
c->pushState();
|
|
||||||
|
|
||||||
c->jg(greater);
|
|
||||||
c->pushState();
|
|
||||||
|
|
||||||
c->push(4, c->constant(0));
|
|
||||||
c->jmp(next);
|
|
||||||
|
|
||||||
c->popState();
|
|
||||||
c->mark(less);
|
|
||||||
|
|
||||||
c->push(4, c->constant(-1));
|
|
||||||
c->jmp(next);
|
|
||||||
|
|
||||||
c->popState();
|
|
||||||
c->mark(greater);
|
|
||||||
|
|
||||||
c->push(4, c->constant(1));
|
|
||||||
|
|
||||||
c->mark(next);
|
|
||||||
|
|
||||||
frame->pushedInt();
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case lconst_0:
|
case lconst_0:
|
||||||
|
@ -1742,7 +1742,7 @@ class CombineEvent: public Event {
|
|||||||
|
|
||||||
removeSite(c, second, second->source);
|
removeSite(c, second, second->source);
|
||||||
if (result->reads) {
|
if (result->reads) {
|
||||||
addSite(c, 0, 0, result, second->source);
|
addSite(c, 0, size, result, second->source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1824,7 +1824,7 @@ class TranslateEvent: public Event {
|
|||||||
|
|
||||||
removeSite(c, value, value->source);
|
removeSite(c, value, value->source);
|
||||||
if (result->reads) {
|
if (result->reads) {
|
||||||
addSite(c, 0, 0, result, value->source);
|
addSite(c, 0, size, result, value->source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2917,6 +2917,13 @@ class MyCompiler: public Compiler {
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Operand* lcmp(Operand* a, Operand* b) {
|
||||||
|
Value* result = value(&c);
|
||||||
|
appendCombine(&c, LongCompare, 8, static_cast<Value*>(a),
|
||||||
|
static_cast<Value*>(b), result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void cmp(unsigned size, Operand* a, Operand* b) {
|
virtual void cmp(unsigned size, Operand* a, Operand* b) {
|
||||||
appendCompare(&c, size, static_cast<Value*>(a),
|
appendCompare(&c, size, static_cast<Value*>(a),
|
||||||
static_cast<Value*>(b));
|
static_cast<Value*>(b));
|
||||||
|
@ -91,6 +91,7 @@ class Compiler {
|
|||||||
virtual Operand* load(unsigned size, Operand* src) = 0;
|
virtual Operand* load(unsigned size, Operand* src) = 0;
|
||||||
virtual Operand* loadz(unsigned size, Operand* src) = 0;
|
virtual Operand* loadz(unsigned size, Operand* src) = 0;
|
||||||
virtual Operand* load4To8(Operand* src) = 0;
|
virtual Operand* load4To8(Operand* src) = 0;
|
||||||
|
virtual Operand* lcmp(Operand* a, Operand* b) = 0;
|
||||||
virtual void cmp(unsigned size, Operand* a, Operand* b) = 0;
|
virtual void cmp(unsigned size, Operand* a, Operand* b) = 0;
|
||||||
virtual void jl(Operand* address) = 0;
|
virtual void jl(Operand* address) = 0;
|
||||||
virtual void jg(Operand* address) = 0;
|
virtual void jg(Operand* address) = 0;
|
||||||
|
284
src/x86.cpp
284
src/x86.cpp
@ -1590,47 +1590,143 @@ unsignedShiftRightCR(Context* c, unsigned size, Assembler::Constant* a,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
multiwordCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah,
|
longCompareCR(Context* c, unsigned size UNUSED, Assembler::Constant* a,
|
||||||
Assembler::Operand* bl, Assembler::Operand* bh,
|
Assembler::Register* b)
|
||||||
BinaryOperationType op)
|
|
||||||
{
|
{
|
||||||
op(c, BytesPerWord, ah, bh);
|
assert(c, size == 8);
|
||||||
|
|
||||||
// if the high order bits are equal, we compare the low order
|
int64_t v = a->value->value();
|
||||||
// bits; otherwise, we jump past that comparison
|
|
||||||
c->code.append(0x0f);
|
ResolvedPromise negativePromise(-1);
|
||||||
c->code.append(0x85); // jne
|
Assembler::Constant negative(&negativePromise);
|
||||||
|
|
||||||
unsigned comparisonOffset = c->code.length();
|
ResolvedPromise zeroPromise(0);
|
||||||
c->code.append4(0);
|
Assembler::Constant zero(&zeroPromise);
|
||||||
|
|
||||||
op(c, BytesPerWord, al, bl);
|
ResolvedPromise positivePromise(1);
|
||||||
|
Assembler::Constant positive(&positivePromise);
|
||||||
|
|
||||||
int32_t comparisonSize = c->code.length() - comparisonOffset - 4;
|
if (BytesPerWord == 8) {
|
||||||
c->code.set(comparisonOffset, &comparisonSize, 4);
|
compareCR(c, 8, a, b);
|
||||||
|
|
||||||
|
c->code.append(0x0f);
|
||||||
|
c->code.append(0x8c); // jl
|
||||||
|
unsigned less = c->code.length();
|
||||||
|
c->code.append4(0);
|
||||||
|
|
||||||
|
c->code.append(0x0f);
|
||||||
|
c->code.append(0x8f); // jg
|
||||||
|
unsigned greater = c->code.length();
|
||||||
|
c->code.append4(0);
|
||||||
|
|
||||||
|
moveCR(c, 4, &zero, b);
|
||||||
|
|
||||||
|
c->code.append(0xe9); // jmp
|
||||||
|
unsigned nextFirst = c->code.length();
|
||||||
|
c->code.append4(0);
|
||||||
|
|
||||||
|
int32_t lessOffset = c->code.length() - less - 4;
|
||||||
|
c->code.set(less, &lessOffset, 4);
|
||||||
|
|
||||||
|
moveCR(c, 4, &negative, b);
|
||||||
|
|
||||||
|
c->code.append(0xe9); // jmp
|
||||||
|
unsigned nextSecond = c->code.length();
|
||||||
|
c->code.append4(0);
|
||||||
|
|
||||||
|
int32_t greaterOffset = c->code.length() - greater - 4;
|
||||||
|
c->code.set(greater, &greaterOffset, 4);
|
||||||
|
|
||||||
|
moveCR(c, 4, &positive, b);
|
||||||
|
|
||||||
|
int32_t nextFirstOffset = c->code.length() - nextFirst - 4;
|
||||||
|
c->code.set(nextFirst, &nextFirstOffset, 4);
|
||||||
|
|
||||||
|
int32_t nextSecondOffset = c->code.length() - nextSecond - 4;
|
||||||
|
c->code.set(nextSecond, &nextSecondOffset, 4);
|
||||||
|
} else {
|
||||||
|
ResolvedPromise low(v & 0xFFFFFFFF);
|
||||||
|
Assembler::Constant al(&low);
|
||||||
|
|
||||||
|
ResolvedPromise high((v >> 32) & 0xFFFFFFFF);
|
||||||
|
Assembler::Constant ah(&high);
|
||||||
|
|
||||||
|
Assembler::Register bh(b->high);
|
||||||
|
|
||||||
|
compareCR(c, 4, &ah, &bh);
|
||||||
|
|
||||||
|
c->code.append(0x0f);
|
||||||
|
c->code.append(0x8c); // jl
|
||||||
|
unsigned less = c->code.length();
|
||||||
|
c->code.append4(0);
|
||||||
|
|
||||||
|
c->code.append(0x0f);
|
||||||
|
c->code.append(0x8f); // jg
|
||||||
|
unsigned greater = c->code.length();
|
||||||
|
c->code.append4(0);
|
||||||
|
|
||||||
|
compareCR(c, 4, &al, b);
|
||||||
|
|
||||||
|
c->code.append(0x0f);
|
||||||
|
c->code.append(0x82); // ja
|
||||||
|
unsigned above = c->code.length();
|
||||||
|
c->code.append4(0);
|
||||||
|
|
||||||
|
c->code.append(0x0f);
|
||||||
|
c->code.append(0x87); // jb
|
||||||
|
unsigned below = c->code.length();
|
||||||
|
c->code.append4(0);
|
||||||
|
|
||||||
|
moveCR(c, 4, &zero, b);
|
||||||
|
|
||||||
|
c->code.append(0xe9); // jmp
|
||||||
|
unsigned nextFirst = c->code.length();
|
||||||
|
c->code.append4(0);
|
||||||
|
|
||||||
|
int32_t lessOffset = c->code.length() - less - 4;
|
||||||
|
c->code.set(less, &lessOffset, 4);
|
||||||
|
|
||||||
|
int32_t aboveOffset = c->code.length() - above - 4;
|
||||||
|
c->code.set(above, &aboveOffset, 4);
|
||||||
|
|
||||||
|
moveCR(c, 4, &negative, b);
|
||||||
|
|
||||||
|
c->code.append(0xe9); // jmp
|
||||||
|
unsigned nextSecond = c->code.length();
|
||||||
|
c->code.append4(0);
|
||||||
|
|
||||||
|
int32_t greaterOffset = c->code.length() - greater - 4;
|
||||||
|
c->code.set(greater, &greaterOffset, 4);
|
||||||
|
|
||||||
|
int32_t belowOffset = c->code.length() - below - 4;
|
||||||
|
c->code.set(below, &belowOffset, 4);
|
||||||
|
|
||||||
|
moveCR(c, 4, &positive, b);
|
||||||
|
|
||||||
|
int32_t nextFirstOffset = c->code.length() - nextFirst - 4;
|
||||||
|
c->code.set(nextFirst, &nextFirstOffset, 4);
|
||||||
|
|
||||||
|
int32_t nextSecondOffset = c->code.length() - nextSecond - 4;
|
||||||
|
c->code.set(nextSecond, &nextSecondOffset, 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
compareRR(Context* c, unsigned size, Assembler::Register* a,
|
compareRR(Context* c, unsigned size, Assembler::Register* a,
|
||||||
Assembler::Register* b)
|
Assembler::Register* b)
|
||||||
{
|
{
|
||||||
if (BytesPerWord == 4 and size == 8) {
|
assert(c, BytesPerWord == 8 or size == 4);
|
||||||
Assembler::Register ah(a->high);
|
|
||||||
Assembler::Register bh(b->high);
|
|
||||||
|
|
||||||
multiwordCompare(c, a, &ah, b, &bh, CAST2(compareRR));
|
if (size == 8) rex(c);
|
||||||
} else {
|
c->code.append(0x39);
|
||||||
if (size == 8) rex(c);
|
c->code.append(0xc0 | (a->low << 3) | b->low);
|
||||||
c->code.append(0x39);
|
|
||||||
c->code.append(0xc0 | (a->low << 3) | b->low);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
compareAR(Context* c, unsigned size, Assembler::Address* a,
|
compareAR(Context* c, unsigned size, Assembler::Address* a,
|
||||||
Assembler::Register* b)
|
Assembler::Register* b)
|
||||||
{
|
{
|
||||||
assert(c, BytesPerWord == 8 or size == 4); // todo
|
assert(c, BytesPerWord == 8 or size == 4);
|
||||||
|
|
||||||
Assembler::Register tmp(c->client->acquireTemporary());
|
Assembler::Register tmp(c->client->acquireTemporary());
|
||||||
moveAR(c, size, a, &tmp);
|
moveAR(c, size, a, &tmp);
|
||||||
@ -1642,36 +1738,26 @@ void
|
|||||||
compareCR(Context* c, unsigned size, Assembler::Constant* a,
|
compareCR(Context* c, unsigned size, Assembler::Constant* a,
|
||||||
Assembler::Register* b)
|
Assembler::Register* b)
|
||||||
{
|
{
|
||||||
|
assert(c, BytesPerWord == 8 or size == 4);
|
||||||
|
|
||||||
int64_t v = a->value->value();
|
int64_t v = a->value->value();
|
||||||
|
|
||||||
if (BytesPerWord == 4 and size == 8) {
|
if (isInt32(v)) {
|
||||||
ResolvedPromise low(v & 0xFFFFFFFF);
|
if (size == 8) rex(c);
|
||||||
Assembler::Constant al(&low);
|
if (isInt8(v)) {
|
||||||
|
c->code.append(0x83);
|
||||||
ResolvedPromise high((v >> 32) & 0xFFFFFFFF);
|
c->code.append(0xf8 | b->low);
|
||||||
Assembler::Constant ah(&high);
|
c->code.append(v);
|
||||||
|
|
||||||
Assembler::Register bh(b->high);
|
|
||||||
|
|
||||||
multiwordCompare(c, &al, &ah, b, &bh, CAST2(compareCR));
|
|
||||||
} else {
|
|
||||||
if (isInt32(v)) {
|
|
||||||
if (size == 8) rex(c);
|
|
||||||
if (isInt8(v)) {
|
|
||||||
c->code.append(0x83);
|
|
||||||
c->code.append(0xf8 | b->low);
|
|
||||||
c->code.append(v);
|
|
||||||
} else {
|
|
||||||
c->code.append(0x81);
|
|
||||||
c->code.append(0xf8 | b->low);
|
|
||||||
c->code.append4(v);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Assembler::Register tmp(c->client->acquireTemporary());
|
c->code.append(0x81);
|
||||||
moveCR(c, size, a, &tmp);
|
c->code.append(0xf8 | b->low);
|
||||||
compareRR(c, size, &tmp, b);
|
c->code.append4(v);
|
||||||
c->client->releaseTemporary(tmp.low);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Assembler::Register tmp(c->client->acquireTemporary());
|
||||||
|
moveCR(c, size, a, &tmp);
|
||||||
|
compareRR(c, size, &tmp, b);
|
||||||
|
c->client->releaseTemporary(tmp.low);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1679,28 +1765,18 @@ void
|
|||||||
compareCM(Context* c, unsigned size, Assembler::Constant* a,
|
compareCM(Context* c, unsigned size, Assembler::Constant* a,
|
||||||
Assembler::Memory* b)
|
Assembler::Memory* b)
|
||||||
{
|
{
|
||||||
|
assert(c, BytesPerWord == 8 or size == 4);
|
||||||
|
|
||||||
int64_t v = a->value->value();
|
int64_t v = a->value->value();
|
||||||
|
|
||||||
if (BytesPerWord == 4 and size == 8) {
|
encode(c, isInt8(v) ? 0x83 : 0x81, 7, b, true);
|
||||||
ResolvedPromise low(v & 0xFFFFFFFF);
|
|
||||||
Assembler::Constant al(&low);
|
|
||||||
|
|
||||||
ResolvedPromise high((v >> 32) & 0xFFFFFFFF);
|
if (isInt8(v)) {
|
||||||
Assembler::Constant ah(&high);
|
c->code.append(v);
|
||||||
|
} else if (isInt32(v)) {
|
||||||
Assembler::Memory bh(b->base, b->offset + 4, b->index, b->scale);
|
c->code.append4(v);
|
||||||
|
|
||||||
multiwordCompare(c, &al, &ah, b, &bh, CAST2(compareCM));
|
|
||||||
} else {
|
} else {
|
||||||
encode(c, isInt8(v) ? 0x83 : 0x81, 7, b, true);
|
abort(c);
|
||||||
|
|
||||||
if (isInt8(v)) {
|
|
||||||
c->code.append(v);
|
|
||||||
} else if (isInt32(v)) {
|
|
||||||
c->code.append4(v);
|
|
||||||
} else {
|
|
||||||
abort(c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1708,75 +1784,48 @@ void
|
|||||||
compareRM(Context* c, unsigned size, Assembler::Register* a,
|
compareRM(Context* c, unsigned size, Assembler::Register* a,
|
||||||
Assembler::Memory* b)
|
Assembler::Memory* b)
|
||||||
{
|
{
|
||||||
if (BytesPerWord == 4 and size == 8) {
|
assert(c, BytesPerWord == 8 or size == 4);
|
||||||
Assembler::Register ah(a->high);
|
|
||||||
Assembler::Memory bh(b->base, b->offset + 4, b->index, b->scale);
|
if (BytesPerWord == 8 and size == 4) {
|
||||||
|
move4To8RR(c, size, a, a);
|
||||||
multiwordCompare(c, a, &ah, b, &bh, CAST2(compareRM));
|
|
||||||
} else {
|
|
||||||
if (BytesPerWord == 8 and size == 4) {
|
|
||||||
move4To8RR(c, size, a, a);
|
|
||||||
}
|
|
||||||
encode(c, 0x39, a->low, b, true);
|
|
||||||
}
|
}
|
||||||
|
encode(c, 0x39, a->low, b, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
compareMR(Context* c, unsigned size, Assembler::Memory* a,
|
compareMR(Context* c, unsigned size, Assembler::Memory* a,
|
||||||
Assembler::Register* b)
|
Assembler::Register* b)
|
||||||
{
|
{
|
||||||
if (BytesPerWord == 4 and size == 8) {
|
assert(c, BytesPerWord == 8 or size == 4);
|
||||||
Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale);
|
|
||||||
Assembler::Register bh(b->high);
|
if (BytesPerWord == 8 and size == 4) {
|
||||||
|
move4To8RR(c, size, b, b);
|
||||||
multiwordCompare(c, a, &ah, b, &bh, CAST2(compareMR));
|
|
||||||
} else {
|
|
||||||
if (BytesPerWord == 8 and size == 4) {
|
|
||||||
move4To8RR(c, size, b, b);
|
|
||||||
}
|
|
||||||
encode(c, 0x3b, b->low, a, true);
|
|
||||||
}
|
}
|
||||||
|
encode(c, 0x3b, b->low, a, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
compareMM(Context* c, unsigned size, Assembler::Memory* a,
|
compareMM(Context* c, unsigned size, Assembler::Memory* a,
|
||||||
Assembler::Memory* b)
|
Assembler::Memory* b)
|
||||||
{
|
{
|
||||||
if (BytesPerWord == 4 and size == 8) {
|
assert(c, BytesPerWord == 8 or size == 4);
|
||||||
Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale);
|
|
||||||
Assembler::Memory bh(b->base, b->offset + 4, b->index, b->scale);
|
Assembler::Register tmp(c->client->acquireTemporary());
|
||||||
|
moveMR(c, size, a, &tmp);
|
||||||
multiwordCompare(c, a, &ah, b, &bh, CAST2(compareMM));
|
compareRM(c, size, &tmp, b);
|
||||||
} else {
|
c->client->releaseTemporary(tmp.low);
|
||||||
Assembler::Register tmp(c->client->acquireTemporary());
|
|
||||||
moveMR(c, size, a, &tmp);
|
|
||||||
compareRM(c, size, &tmp, b);
|
|
||||||
c->client->releaseTemporary(tmp.low);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
compareRC(Context* c, unsigned size, Assembler::Register* a,
|
compareRC(Context* c, unsigned size, Assembler::Register* a,
|
||||||
Assembler::Constant* b)
|
Assembler::Constant* b)
|
||||||
{
|
{
|
||||||
if (BytesPerWord == 4 and size == 8) {
|
assert(c, BytesPerWord == 8 or size == 4);
|
||||||
Assembler::Register ah(a->high);
|
|
||||||
|
Assembler::Register tmp(c->client->acquireTemporary());
|
||||||
int64_t v = b->value->value();
|
moveCR(c, size, b, &tmp);
|
||||||
|
compareRR(c, size, a, &tmp);
|
||||||
ResolvedPromise low(v & 0xFFFFFFFF);
|
c->client->releaseTemporary(tmp.low);
|
||||||
Assembler::Constant bl(&low);
|
|
||||||
|
|
||||||
ResolvedPromise high((v >> 32) & 0xFFFFFFFF);
|
|
||||||
Assembler::Constant bh(&high);
|
|
||||||
|
|
||||||
multiwordCompare(c, a, &ah, &bl, &bh, CAST2(compareRC));
|
|
||||||
} else {
|
|
||||||
Assembler::Register tmp(c->client->acquireTemporary());
|
|
||||||
moveCR(c, size, b, &tmp);
|
|
||||||
compareRR(c, size, a, &tmp);
|
|
||||||
c->client->releaseTemporary(tmp.low);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1882,6 +1931,9 @@ populateTables()
|
|||||||
BinaryOperations[INDEX2(Subtract, Constant, Register)] = CAST2(subtractCR);
|
BinaryOperations[INDEX2(Subtract, Constant, Register)] = CAST2(subtractCR);
|
||||||
BinaryOperations[INDEX2(Subtract, Register, Register)] = CAST2(subtractRR);
|
BinaryOperations[INDEX2(Subtract, Register, Register)] = CAST2(subtractRR);
|
||||||
|
|
||||||
|
BinaryOperations[INDEX2(LongCompare, Constant, Register)]
|
||||||
|
= CAST2(longCompareCR);
|
||||||
|
|
||||||
BinaryOperations[INDEX2(Compare, Constant, Register)] = CAST2(compareCR);
|
BinaryOperations[INDEX2(Compare, Constant, Register)] = CAST2(compareCR);
|
||||||
BinaryOperations[INDEX2(Compare, Register, Constant)] = CAST2(compareRC);
|
BinaryOperations[INDEX2(Compare, Register, Constant)] = CAST2(compareRC);
|
||||||
BinaryOperations[INDEX2(Compare, Register, Register)] = CAST2(compareRR);
|
BinaryOperations[INDEX2(Compare, Register, Register)] = CAST2(compareRR);
|
||||||
|
Loading…
Reference in New Issue
Block a user