replace compare and branch instructions with combined versions

This allows the assembler to see the operand types of the comparison
and the condition for jumping in the same operation, which is
essential for generating efficient code in cases such as
multiple-precision compare-and-branch.
This commit is contained in:
Joel Dice 2009-10-10 15:03:23 -06:00
parent 609a1a9633
commit 622b3d1c4e
4 changed files with 699 additions and 576 deletions

View File

@ -49,10 +49,8 @@ enum BinaryOperation {
MoveLow,
MoveHigh,
MoveZ,
Compare,
Negate,
FloatNegate,
FloatCompare,
Float2Float,
Float2Int,
Int2Float,

View File

@ -2689,8 +2689,8 @@ saveStateAndCompile(MyThread* t, Frame* initialFrame, unsigned ip)
}
bool
integerBranch(Frame* frame, object code, unsigned& ip, unsigned size,
Compiler::Operand* a, Compiler::Operand* b)
integerBranch(MyThread* t, Frame* frame, object code, unsigned& ip,
unsigned size, Compiler::Operand* a, Compiler::Operand* b)
{
if (ip + 3 > codeLength(t, code)) {
return false;
@ -2707,37 +2707,41 @@ integerBranch(Frame* frame, object code, unsigned& ip, unsigned size,
switch (instruction) {
case ifeq:
c->jumpIfEqual(size, a, b, target);
return true;
break;
case ifne:
c->jumpIfNotEqual(size, a, b, target);
return true;
break;
case ifgt:
c->jumpIfGreater(size, a, b, target);
return true;
break;
case ifge:
c->jumpIfGreaterOrEqual(size, a, b, target);
return true;
break;
case iflt:
c->jumpIfLessOrUnordered(size, a, b, target);
return true;
c->jumpIfLess(size, a, b, target);
break;
case ifle:
c->jumpIfLessOrEqualOrUnordered(size, a, b, target);
return true;
c->jumpIfLessOrEqual(size, a, b, target);
break;
default:
ip -= 3;
return false;
}
saveStateAndCompile(t, frame, newIp);
return t->exception == 0;
}
bool
floatBranch(Frame* frame, object code, unsigned& ip, unsigned size,
bool lessIfUnordered, Compiler::Operand* a, Compiler::Operand* b)
floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip,
unsigned size, bool lessIfUnordered, Compiler::Operand* a,
Compiler::Operand* b)
{
if (ip + 3 > codeLength(t, code)) {
return false;
@ -2754,11 +2758,11 @@ floatBranch(Frame* frame, object code, unsigned& ip, unsigned size,
switch (instruction) {
case ifeq:
c->jumpIfFloatEqual(size, a, b, target);
return true;
break;
case ifne:
c->jumpIfFloatNotEqual(size, a, b, target);
return true;
break;
case ifgt:
if (lessIfUnordered) {
@ -2766,7 +2770,7 @@ floatBranch(Frame* frame, object code, unsigned& ip, unsigned size,
} else {
c->jumpIfFloatGreaterOrUnordered(size, a, b, target);
}
return true;
break;
case ifge:
if (lessIfUnordered) {
@ -2774,7 +2778,7 @@ floatBranch(Frame* frame, object code, unsigned& ip, unsigned size,
} else {
c->jumpIfFloatGreaterOrEqualOrUnordered(size, a, b, target);
}
return true;
break;
case iflt:
if (lessIfUnordered) {
@ -2782,7 +2786,7 @@ floatBranch(Frame* frame, object code, unsigned& ip, unsigned size,
} else {
c->jumpIfFloatLess(size, a, b, target);
}
return true;
break;
case ifle:
if (lessIfUnordered) {
@ -2790,12 +2794,15 @@ floatBranch(Frame* frame, object code, unsigned& ip, unsigned size,
} else {
c->jumpIfFloatLessOrEqual(size, a, b, target);
}
return true;
break;
default:
ip -= 3;
return false;
}
saveStateAndCompile(t, frame, newIp);
return t->exception == 0;
}
void
@ -3144,7 +3151,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
if (not floatBranch(frame, ip, 8, false, a, b)) {
if (not floatBranch(t, frame, code, ip, 8, false, a, b)) {
if (UNLIKELY(t->exception)) return;
frame->pushInt
(c->call
(c->constant
@ -3159,7 +3168,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
if (not floatBranch(frame, ip, 8, true, a, b)) {
if (not floatBranch(t, frame, code, ip, 8, true, a, b)) {
if (UNLIKELY(t->exception)) return;
frame->pushInt
(c->call
(c->constant
@ -3257,7 +3268,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
if (not floatBranch(frame, ip, 4, false, a, b)) {
if (not floatBranch(t, frame, code, ip, 4, false, a, b)) {
if (UNLIKELY(t->exception)) return;
frame->pushInt
(c->call
(c->constant
@ -3270,7 +3283,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
if (not floatBranch(frame, ip, 4, true, a, b)) {
if (not floatBranch(t, frame, code, ip, 4, true, a, b)) {
if (UNLIKELY(t->exception)) return;
frame->pushInt
(c->call
(c->constant
@ -3563,9 +3578,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
Compiler::Operand* target = frame->machineIp(newIp);
if (instruction == if_acmpeq) {
c->jumpIfEqual(BytesPerWord, a, btarget);
c->jumpIfEqual(BytesPerWord, a, b, target);
} else {
c->jumpIfNotEqual(BytesPerWord, a, btarget);
c->jumpIfNotEqual(BytesPerWord, a, b, target);
}
saveStateAndCompile(t, frame, newIp);
@ -3624,7 +3639,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
assert(t, newIp < codeLength(t, code));
Compiler::Operand* target = frame->machineIp(newIp);
Compiler::Operand* cont = frame->machineIp(ip);
Compiler::Operand* a = c->constant(0, Compiler::IntegerType);
Compiler::Operand* b = frame->popInt();
@ -3667,9 +3681,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
Compiler::Operand* target = frame->machineIp(newIp);
if (instruction == ifnull) {
c->jumpIfEqual(BytesPerWord, a, btarget);
c->jumpIfEqual(BytesPerWord, a, b, target);
} else {
c->jumpIfNotEqual(BytesPerWord, a, btarget);
c->jumpIfNotEqual(BytesPerWord, a, b, target);
}
saveStateAndCompile(t, frame, newIp);
@ -4023,7 +4037,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
if (not integerBranch(frame, ip, 8, a, b)) {
if (not integerBranch(t, frame, code, ip, 8, a, b)) {
if (UNLIKELY(t->exception)) return;
frame->pushInt
(c->call
(c->constant

View File

@ -31,7 +31,10 @@ const int AnyFrameIndex = -2;
const int NoFrameIndex = -1;
const unsigned StealRegisterReserveCount = 2;
const unsigned ResolveRegisterReserveCount = 2;
// this should be equal to the largest number of registers used by a
// compare instruction:
const unsigned ResolveRegisterReserveCount = (BytesPerWord == 8 ? 2 : 4);
class Context;
class Value;
@ -3263,7 +3266,6 @@ grow(Context* c, Value* v)
assert(c, v->next == v);
Value* next = value(c, v->type);
fprintf(stderr, "grow %p to %p\n", v, next);
v->next = next;
next->next = v;
next->index = 1;
@ -3583,8 +3585,8 @@ class CombineEvent: public Event {
// fprintf(stderr, "combine %p and %p into %p\n", first, second, result);
apply(c, type,
firstSize, first->source, first->next->source),
secondSize, second->source, second->next->source),
firstSize, first->source, first->next->source,
secondSize, second->source, second->next->source,
resultSize, low, high);
thawSource(c, firstSize, first);
@ -4004,7 +4006,7 @@ class TranslateEvent: public Event {
? getTarget(c, value->next, result->next, resultHighMask)
: low);
apply(c, type, valueSize, value->source, value->next->source),
apply(c, type, valueSize, value->source, value->next->source,
resultSize, low, high);
for (Read* r = reads; r; r = r->eventNext) {
@ -4189,7 +4191,8 @@ unordered(double a, double b)
}
bool
shouldJump(TernaryOperation type, unsigned size, int64_t a, int64_t b)
shouldJump(Context* c, TernaryOperation type, unsigned size, int64_t b,
int64_t a)
{
switch (type) {
case JumpIfEqual:
@ -4245,23 +4248,30 @@ shouldJump(TernaryOperation type, unsigned size, int64_t a, int64_t b)
or unordered(asFloat(size, a), asFloat(size, b));
default:
jump = false;
abort(c);
}
}
class BranchEvent: public Event {
public:
BranchEvent(Context* c, TernaryOperation type, unsigned size,
Value* first, Value* second, Value* address, bool exit,
Value* first, Value* second, Value* address,
const SiteMask& firstLowMask,
const SiteMask& firstHighMask,
const SiteMask& secondLowMask,
const SiteMask& secondHighMask):
Event(c), type(type), size(size), first(first), second(second),
address(address), exit(exit)
address(address)
{
addReads(c, this, first, firstSize, firstLowMask, firstHighMask);
addReads(c, this, second, secondSize, secondLowMask, secondHighMask);
addReads(c, this, first, size, firstLowMask, firstHighMask);
addReads(c, this, second, size, secondLowMask, secondHighMask);
uint8_t typeMask;
uint64_t registerMask;
c->arch->planDestination(type, size, 0, 0, size, 0, 0, BytesPerWord,
&typeMask, &registerMask);
addRead(c, this, address, SiteMask(typeMask, registerMask, AnyFrameIndex));
}
virtual const char* name() {
@ -4274,15 +4284,14 @@ class BranchEvent: public Event {
if (not unreachable(this)) {
if (firstConstant and secondConstant) {
if (shouldJump(type, firstConstant->value->value(),
secondConstant->value->value())
and reachable)
if (shouldJump(c, type, size, firstConstant->value->value(),
secondConstant->value->value()))
{
apply(c, Jump, BytesPerWord, address->source, address->source);
}
} else {
apply(c, type, size, first->source, first->next->source,
size, second->source, second->next->sourcem
size, second->source, second->next->source,
BytesPerWord, address->source, address->source);
}
}
@ -4294,21 +4303,16 @@ class BranchEvent: public Event {
virtual bool isBranch() { return true; }
virtual bool allExits() {
return type == Jump and (exit or unreachable(this));
}
UnaryOperation type;
TernaryOperation type;
unsigned size;
Value* first;
Value* second;
Value* address;
bool exit;
};
void
appendBranch(Context* c, TernaryOperation type, unsigned size, Value* first,
Value* second, Value* address, bool exit = false)
Value* second, Value* address)
{
bool thunk;
uint8_t firstTypeMask;
@ -4318,7 +4322,7 @@ appendBranch(Context* c, TernaryOperation type, unsigned size, Value* first,
c->arch->planSource(type, size, &firstTypeMask, &firstRegisterMask,
size, &secondTypeMask, &secondRegisterMask,
resultSize, &thunk);
BytesPerWord, &thunk);
if (thunk) {
Stack* oldStack = c->stack;
@ -4329,20 +4333,21 @@ appendBranch(Context* c, TernaryOperation type, unsigned size, Value* first,
Stack* argumentStack = c->stack;
c->stack = oldStack;
Value* result = value(&c, ValueGeneral);
Value* result = value(c, ValueGeneral);
appendCall
(c, value
(c, ValueGeneral, constantSite(c, c->client->getThunk(type, size, 4))),
0, 0, result, resultSize, argumentStack,
0, 0, result, 4, argumentStack,
ceiling(size, BytesPerWord) * 2, 0);
appendBranch(c, JumpIfEqual, 4, value(c, ValueGeneral, constantSite(c, 0)),
appendBranch(c, JumpIfEqual, 4, value
(c, ValueGeneral, constantSite(c, static_cast<int64_t>(0))),
result, address);
} else {
append
(c, new (c->zone->allocate(sizeof(BranchEvent)))
BranchEvent
(c, type, size, first, second, address, exit,
(c, type, size, first, second, address,
SiteMask(firstTypeMask, firstRegisterMask, AnyFrameIndex),
SiteMask(firstTypeMask, firstRegisterMask >> 32, AnyFrameIndex),
SiteMask(secondTypeMask, secondRegisterMask, AnyFrameIndex),
@ -4350,12 +4355,51 @@ appendBranch(Context* c, TernaryOperation type, unsigned size, Value* first,
}
}
class JumpEvent: public Event {
public:
JumpEvent(Context* c, UnaryOperation type, Value* address, bool exit):
Event(c), type(type), address(address), exit(exit)
{
bool thunk;
uint8_t typeMask;
uint64_t registerMask;
c->arch->plan(type, BytesPerWord, &typeMask, &registerMask, &thunk);
assert(c, not thunk);
addRead(c, this, address, SiteMask(typeMask, registerMask, AnyFrameIndex));
}
virtual const char* name() {
return "JumpEvent";
}
virtual void compile(Context* c) {
if (not unreachable(this)) {
apply(c, type, BytesPerWord, address->source, address->source);
}
for (Read* r = reads; r; r = r->eventNext) {
popRead(c, this, r->value);
}
}
virtual bool isBranch() { return true; }
virtual bool allExits() {
return exit or unreachable(this);
}
UnaryOperation type;
Value* address;
bool exit;
};
void
appendBranch(Context* c, UnaryOperation type, Value* address,
bool exit = false)
appendJump(Context* c, UnaryOperation type, Value* address, bool exit = false)
{
append(c, new (c->zone->allocate(sizeof(BranchEvent)))
BranchEvent(c, type, address, exit));
append(c, new (c->zone->allocate(sizeof(JumpEvent)))
JumpEvent(c, type, address, exit));
}
class BoundsCheckEvent: public Event {
@ -4386,11 +4430,10 @@ class BoundsCheckEvent: public Event {
} else {
outOfBoundsPromise = codePromise(c, static_cast<Promise*>(0));
Site* zero = constantSite(c, resolved(c, 0));
Assembler::Constant outOfBoundsConstant(outOfBoundsPromise);
a->apply
(JumpIfLess, 4, zero, zero, 4, index->source, index->source,
BytesPerWord, ConstantOperand, &outOfBoundsConstant);
ConstantSite zero(resolved(c, 0));
ConstantSite oob(outOfBoundsPromise);
apply(c, JumpIfLess, 4, &zero, &zero, 4, index->source, index->source,
BytesPerWord, &oob, &oob);
}
assert(c, object->source->type(c) == RegisterOperand);
@ -4398,9 +4441,9 @@ class BoundsCheckEvent: public Event {
lengthOffset, NoRegister, 1);
length.acquired = true;
Assembler::Constant nextConstant(nextPromise);
a->apply(JumpIfGreater, 4, index->source, index->source, 4, &length,
&length, BytesPerWord, ConstantOperand, &nextConstant);
ConstantSite next(nextPromise);
apply(c, JumpIfGreater, 4, index->source, index->source, 4, &length,
&length, BytesPerWord, &next, &next);
if (constant == 0) {
outOfBoundsPromise->offset = a->offset();
@ -6107,11 +6150,11 @@ class MyCompiler: public Compiler {
}
virtual void jmp(Operand* address) {
appendBranch(&c, Jump, 0, 0, 0, static_cast<Value*>(address));
appendJump(&c, Jump, static_cast<Value*>(address));
}
virtual void exit(Operand* address) {
appendBranch(&c, Jump, 0, 0, 0, static_cast<Value*>(address), true);
appendJump(&c, Jump, static_cast<Value*>(address), true);
}
virtual Operand* add(unsigned size, Operand* a, Operand* b) {

File diff suppressed because it is too large Load Diff