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, MoveLow,
MoveHigh, MoveHigh,
MoveZ, MoveZ,
Compare,
Negate, Negate,
FloatNegate, FloatNegate,
FloatCompare,
Float2Float, Float2Float,
Float2Int, Float2Int,
Int2Float, Int2Float,

View File

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

View File

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

File diff suppressed because it is too large Load Diff