diff --git a/src/assembler.h b/src/assembler.h index 6922f2b55d..732e75a97e 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -23,7 +23,6 @@ enum Operation { const unsigned OperationCount = Return + 1; enum UnaryOperation { - PushFrame, Call, LongCall, AlignedCall, @@ -34,20 +33,20 @@ enum UnaryOperation { JumpIfLessOrEqual, JumpIfGreaterOrEqual, JumpIfEqual, - JumpIfNotEqual, - Negate + JumpIfNotEqual }; -const unsigned UnaryOperationCount = Negate + 1; +const unsigned UnaryOperationCount = JumpIfNotEqual + 1; enum BinaryOperation { Move, MoveZ, Swap, - Compare + Compare, + Negate }; -const unsigned BinaryOperationCount = Compare + 1; +const unsigned BinaryOperationCount = Negate + 1; enum TernaryOperation { LongCompare, @@ -172,7 +171,6 @@ class Assembler { virtual unsigned registerCount() = 0; virtual int stack() = 0; - virtual int base() = 0; virtual int thread() = 0; virtual int returnLow() = 0; virtual int returnHigh() = 0; @@ -241,12 +239,13 @@ class Assembler { virtual void dispose() = 0; }; -Assembler* -makeAssembler(System* system, Allocator* allocator, Zone* zone); - Assembler::Architecture* makeArchitecture(System* system); +Assembler* +makeAssembler(System* system, Allocator* allocator, Zone* zone, + Assembler::Architecture* architecture); + } // namespace vm #endif//ASSEMBLER_H diff --git a/src/compile.cpp b/src/compile.cpp index 517f598a22..86982676e6 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -517,7 +517,7 @@ class Context { Context(MyThread* t, object method): thread(t), zone(t->m->system, t->m->heap, 16 * 1024), - assembler(makeAssembler(t->m->system, t->m->heap, &zone)), + assembler(makeAssembler(t->m->system, t->m->heap, &zone, t->arch)), client(t), compiler(makeCompiler(t->m->system, assembler, &zone, &client)), method(method), @@ -533,7 +533,7 @@ class Context { Context(MyThread* t): thread(t), zone(t->m->system, t->m->heap, LikelyPageSizeInBytes), - assembler(makeAssembler(t->m->system, t->m->heap, &zone)), + assembler(makeAssembler(t->m->system, t->m->heap, &zone, t->arch)), client(t), compiler(0), method(0), diff --git a/src/finder.cpp b/src/finder.cpp index 973439b927..57863d5f07 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -16,14 +16,6 @@ using namespace vm; namespace { -void* -allocate(System* s, unsigned size) -{ - void* p = s->tryAllocate(size); - if (p == 0) abort(); - return p; -} - const char* append(System* s, const char* a, const char* b, const char* c) diff --git a/src/posix.cpp b/src/posix.cpp index 38fb515d6b..1afece6113 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -77,14 +77,6 @@ run(void* r) return 0; } -void* -allocate(System* s, unsigned size) -{ - void* p = s->tryAllocate(size); - if (p == 0) abort(); - return p; -} - void pathOfExecutable(System* s, const char** retBuf, unsigned* size) { diff --git a/src/system.h b/src/system.h index 3771010606..4223451756 100644 --- a/src/system.h +++ b/src/system.h @@ -148,6 +148,14 @@ class System { virtual void dispose() = 0; }; +inline void* +allocate(System* s, unsigned size) +{ + void* p = s->tryAllocate(size); + if (p == 0) s->abort(); + return p; +} + #define ACQUIRE_MONITOR(t, m) \ System::MonitorResource MAKE_NAME(monitorResource_) (t, m) diff --git a/src/x86.cpp b/src/x86.cpp index e45cb97a05..18f601a697 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -13,17 +13,6 @@ using namespace vm; -#define INDEX1(a, b) ((a) + (UnaryOperationCount * (b))) - -#define CAST1(x) reinterpret_cast(x) - -#define INDEX2(a, b, c) \ - ((a) \ - + (BinaryOperationCount * (b)) \ - + (BinaryOperationCount * OperandTypeCount * (c))) - -#define CAST2(x) reinterpret_cast(x) - namespace { enum { @@ -73,18 +62,58 @@ class Context { uint8_t* result; }; +typedef void (*OperationType)(Context*); + +typedef void (*UnaryOperationType)(Context*, unsigned, Assembler::Operand*); + +typedef void (*BinaryOperationType) +(Context*, unsigned, Assembler::Operand*, unsigned, Assembler::Operand*); + +typedef void (*TernaryOperationType) +(Context*, unsigned, Assembler::Operand*, unsigned, Assembler::Operand*, + unsigned, Assembler::Operand*); + +class ArchitectureContext { + public: + ArchitectureContext(System* s): s(s) { } + + System* s; + OperationType operations[OperationCount]; + UnaryOperationType unaryOperations[UnaryOperationCount + * OperandTypeCount]; + BinaryOperationType binaryOperations[BinaryOperationCount + * OperandTypeCount + * OperandTypeCount]; + TernaryOperationType ternaryOperations[TernaryOperationCount + * OperandTypeCount + * OperandTypeCount + * OperandTypeCount]; +}; + inline void NO_RETURN abort(Context* c) { abort(c->s); } +inline void NO_RETURN +abort(ArchitectureContext* c) +{ + abort(c->s); +} + #ifndef NDEBUG inline void assert(Context* c, bool v) { assert(c->s, v); } + +inline void +assert(ArchitectureContext* c, bool v) +{ + assert(c->s, v); +} #endif // not NDEBUG inline void @@ -266,19 +295,6 @@ encode2(Context* c, uint16_t instruction, int a, Assembler::Memory* b, encode(c, i, 2, a, b->base, b->offset, b->index, b->scale); } -typedef void (*OperationType)(Context*); -OperationType -Operations[OperationCount]; - -typedef void (*UnaryOperationType)(Context*, unsigned, Assembler::Operand*); -UnaryOperationType -UnaryOperations[UnaryOperationCount * OperandTypeCount]; - -typedef void (*BinaryOperationType) -(Context*, unsigned, Assembler::Operand*, Assembler::Operand*); -BinaryOperationType -BinaryOperations[BinaryOperationCount * OperandTypeCount * OperandTypeCount]; - void return_(Context* c) { @@ -304,1728 +320,59 @@ conditional(Context* c, unsigned condition, Assembler::Constant* a) c->code.append4(0); } -void -moveCR(Context*, unsigned, Assembler::Constant*, Assembler::Register*); - -void -callR(Context*, unsigned, Assembler::Register*); - -void -callC(Context* c, unsigned size UNUSED, Assembler::Constant* a) -{ - assert(c, size == BytesPerWord); - - unconditional(c, 0xe8, a); -} - -void -longCallC(Context* c, unsigned size, Assembler::Constant* a) -{ - assert(c, size == BytesPerWord); - - if (BytesPerWord == 8) { - Assembler::Register r(r10); - moveCR(c, size, a, &r); - callR(c, size, &r); - } else { - callC(c, size, a); - } -} - -void -alignedCallC(Context* c, unsigned size, Assembler::Constant* a) -{ - while ((c->code.length() + 1) % 4) { - c->code.append(0x90); - } - callC(c, size, a); -} - -void -callR(Context* c, unsigned size UNUSED, Assembler::Register* a) -{ - assert(c, size == BytesPerWord); - - if (a->low & 8) rex(c, 0x40, a->low); - c->code.append(0xff); - c->code.append(0xd0 | (a->low & 7)); -} - -void -callM(Context* c, unsigned size UNUSED, Assembler::Memory* a) -{ - assert(c, size == BytesPerWord); - - encode(c, 0xff, 2, a, false); -} - -void -jumpR(Context* c, unsigned size UNUSED, Assembler::Register* a) -{ - assert(c, size == BytesPerWord); - - if (a->low & 8) rex(c, 0x40, a->low); - c->code.append(0xff); - c->code.append(0xe0 | (a->low & 7)); -} - -void -jumpC(Context* c, unsigned size UNUSED, Assembler::Constant* a) -{ - assert(c, size == BytesPerWord); - - unconditional(c, 0xe9, a); -} - -void -longJumpC(Context* c, unsigned size, Assembler::Constant* a) -{ - assert(c, size == BytesPerWord); - - if (BytesPerWord == 8) { - Assembler::Register r(r10); - moveCR(c, size, a, &r); - jumpR(c, size, &r); - } else { - jumpC(c, size, a); - } -} - -void -jumpM(Context* c, unsigned size UNUSED, Assembler::Memory* a) -{ - assert(c, size == BytesPerWord); - - encode(c, 0xff, 4, a, false); -} - -void -jumpIfEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* a) -{ - assert(c, size == BytesPerWord); - - conditional(c, 0x84, a); -} - -void -jumpIfNotEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* a) -{ - assert(c, size == BytesPerWord); - - conditional(c, 0x85, a); -} - -void -jumpIfGreaterC(Context* c, unsigned size UNUSED, Assembler::Constant* a) -{ - assert(c, size == BytesPerWord); - - conditional(c, 0x8f, a); -} - -void -jumpIfGreaterOrEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* a) -{ - assert(c, size == BytesPerWord); - - conditional(c, 0x8d, a); -} - -void -jumpIfLessC(Context* c, unsigned size UNUSED, Assembler::Constant* a) -{ - assert(c, size == BytesPerWord); - - conditional(c, 0x8c, a); -} - -void -jumpIfLessOrEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* a) -{ - assert(c, size == BytesPerWord); - - conditional(c, 0x8e, a); -} - -void -pushR(Context*, unsigned, Assembler::Register*); - -void -pushC(Context* c, unsigned size, Assembler::Constant* a) -{ - if (BytesPerWord == 4 and size == 8) { - int64_t v = a->value->value(); - - ResolvedPromise low(v & 0xFFFFFFFF); - Assembler::Constant al(&low); - - ResolvedPromise high((v >> 32) & 0xFFFFFFFF); - Assembler::Constant ah(&high); - - pushC(c, 4, &ah); - pushC(c, 4, &al); - } else { - if (a->value->resolved()) { - int64_t v = a->value->value(); - if (isInt8(v)) { - c->code.append(0x6a); - c->code.append(v); - } else if (isInt32(v)) { - c->code.append(0x68); - c->code.append4(v); - } else { - Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - pushR(c, size, &tmp); - c->client->releaseTemporary(tmp.low); - } - } else { - if (BytesPerWord == 4) { - c->code.append(0x68); - appendImmediateTask(c, a->value, c->code.length()); - c->code.appendAddress(static_cast(0)); - } else { - Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - pushR(c, size, &tmp); - c->client->releaseTemporary(tmp.low); - } - } - } -} - -void -moveAR(Context*, unsigned, Assembler::Address*, Assembler::Register* b); - -void -pushA(Context* c, unsigned size, Assembler::Address* a) -{ - assert(c, BytesPerWord == 8 or size == 4); // todo - - Assembler::Register tmp(c->client->acquireTemporary()); - moveAR(c, size, a, &tmp); - pushR(c, size, &tmp); - c->client->releaseTemporary(tmp.low); -} - -void -pushR(Context* c, unsigned size, Assembler::Register* a) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Register ah(a->high); - - pushR(c, 4, &ah); - pushR(c, 4, a); - } else { - c->code.append(0x50 | a->low); - } -} - -void -pushM(Context* c, unsigned size, Assembler::Memory* a) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); - - pushM(c, 4, &ah); - pushM(c, 4, a); - } else { - assert(c, BytesPerWord == 4 or size == 8); - - encode(c, 0xff, 6, a, false); - } -} - -void -move4To8RR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b); - -void -popR(Context* c, unsigned size, Assembler::Register* a) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Register ah(a->high); - - popR(c, 4, a); - popR(c, 4, &ah); - } else { - c->code.append(0x58 | a->low); - if (BytesPerWord == 8 and size == 4) { - move4To8RR(c, 0, a, a); - } - } -} - -void -popM(Context* c, unsigned size, Assembler::Memory* a) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); - - popM(c, 4, a); - popM(c, 4, &ah); - } else { - assert(c, BytesPerWord == 4 or size == 8); - - encode(c, 0x8f, 0, a, false); - } -} - -void -addCarryCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - int64_t v = a->value->value(); - if (isInt8(v)) { - c->code.append(0x83); - c->code.append(0xd0 | b->low); - c->code.append(v); - } else { - abort(c); - } -} - -void -moveRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b); - -void -xorRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b); - -void -negateR(Context* c, unsigned size, Assembler::Register* a) -{ - if (BytesPerWord == 4 and size == 8) { - assert(c, a->low == rax and a->high == rdx); - - ResolvedPromise zeroPromise(0); - Assembler::Constant zero(&zeroPromise); - - Assembler::Register ah(a->high); - - negateR(c, 4, a); - addCarryCR(c, 4, &zero, &ah); - negateR(c, 4, &ah); - } else { - if (size == 8) rex(c); - c->code.append(0xf7); - c->code.append(0xd8 | a->low); - } -} - -void -leaMR(Context* c, unsigned size, Assembler::Memory* b, Assembler::Register* a) -{ - if (BytesPerWord == 8 and size == 4) { - encode(c, 0x8d, a->low, b, false); - } else { - assert(c, BytesPerWord == 8 or size == 4); - - encode(c, 0x8d, a->low, b, true); - } -} - -void -moveCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - if (BytesPerWord == 4 and size == 8) { - int64_t v = a->value->value(); - - ResolvedPromise high((v >> 32) & 0xFFFFFFFF); - Assembler::Constant ah(&high); - - ResolvedPromise low(v & 0xFFFFFFFF); - Assembler::Constant al(&low); - - Assembler::Register bh(b->high); - - moveCR(c, 4, &al, b); - moveCR(c, 4, &ah, &bh); - } else { - rex(c, 0x48, b->low); - c->code.append(0xb8 | b->low); - if (a->value->resolved()) { - c->code.appendAddress(a->value->value()); - } else { - appendImmediateTask(c, a->value, c->code.length()); - c->code.appendAddress(static_cast(0)); - } - } -} - -void -moveCM(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Memory* b) -{ - int64_t v = a->value->value(); - - switch (size) { - case 1: - encode(c, 0xc6, 0, b, false); - c->code.append(a->value->value()); - break; - - case 2: - encode2(c, 0x66c7, 0, b, false); - c->code.append2(a->value->value()); - break; - - case 4: - encode(c, 0xc7, 0, b, false); - c->code.append4(a->value->value()); - break; - - case 8: { - ResolvedPromise high((v >> 32) & 0xFFFFFFFF); - Assembler::Constant ah(&high); - - ResolvedPromise low(v & 0xFFFFFFFF); - Assembler::Constant al(&low); - - Assembler::Memory bh(b->base, b->offset + 4, b->index, b->scale); - - moveCM(c, 4, &al, b); - moveCM(c, 4, &ah, &bh); - } break; - - default: abort(c); - } -} - -void -moveRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Register ah(a->high); - Assembler::Register bh(b->high); - - moveRR(c, 4, a, b); - moveRR(c, 4, &ah, &bh); - } else { - switch (size) { - case 1: - if (BytesPerWord == 4 and a->low > rbx) { - assert(c, b->low <= rbx); - - moveRR(c, BytesPerWord, a, b); - moveRR(c, 1, b, b); - } else { - rex(c); - c->code.append(0x0f); - c->code.append(0xbe); - c->code.append(0xc0 | (b->low << 3) | a->low); - } - break; - - case 2: - rex(c); - c->code.append(0x0f); - c->code.append(0xbf); - c->code.append(0xc0 | (b->low << 3) | a->low); - break; - - case 8: - case 4: - if (a->low != b->low) { - rex(c); - c->code.append(0x89); - c->code.append(0xc0 | (a->low << 3) | b->low); - } - break; - } - } -} - -void -moveRM(Context* c, unsigned size, Assembler::Register* a, Assembler::Memory* b) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Register ah(a->high); - Assembler::Memory bh(b->base, b->offset + 4, b->index, b->scale); - - moveRM(c, 4, a, b); - moveRM(c, 4, &ah, &bh); - } else if (BytesPerWord == 8 and size == 4) { - encode(c, 0x89, a->low, b, false); - } else { - switch (size) { - case 1: - if (BytesPerWord == 8) { - if (a->low > rbx) { - encode2(c, 0x4088, a->low, b, false); - } else { - encode(c, 0x88, a->low, b, false); - } - } else { - assert(c, a->low <= rbx); - - encode(c, 0x88, a->low, b, false); - } - break; - - case 2: - encode2(c, 0x6689, a->low, b, false); - break; - - case BytesPerWord: - encode(c, 0x89, a->low, b, true); - break; - - default: abort(c); - } - } -} - -void -move4To8CR(Context* c, unsigned, Assembler::Constant* a, - Assembler::Register* b) -{ - moveCR(c, 8, a, b); -} - -void -move4To8RR(Context* c, unsigned, Assembler::Register* a, - Assembler::Register* b) -{ - if (BytesPerWord == 8) { - rex(c); - c->code.append(0x63); - c->code.append(0xc0 | (b->low << 3) | a->low); - } else { - if (a->low == rax and b->low == rax and b->high == rdx) { - c->code.append(0x99); // cdq - } else { - assert(c, b->low == rax and b->high == rdx); - - moveRR(c, 4, a, b); - move4To8RR(c, 0, b, b); - } - } -} - -void -moveMR(Context* c, unsigned size, Assembler::Memory* a, Assembler::Register* b) -{ - switch (size) { - case 1: - encode2(c, 0x0fbe, b->low, a, true); - break; - - case 2: - encode2(c, 0x0fbf, b->low, a, true); - break; - - case 4: - case 8: - if (BytesPerWord == 4 and size == 8) { - Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); - Assembler::Register bh(b->high); - - moveMR(c, 4, a, b); - moveMR(c, 4, &ah, &bh); - } else if (BytesPerWord == 8 and size == 4) { - encode(c, 0x63, b->low, a, true); - } else { - encode(c, 0x8b, b->low, a, true); - } - break; - - default: abort(c); - } -} - -void -moveAR(Context* c, unsigned size, Assembler::Address* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); // todo - - Assembler::Constant constant(a->address); - Assembler::Memory memory(b->low, 0, -1, 0); - - moveCR(c, size, &constant, b); - moveMR(c, size, &memory, b); -} - -void -moveAM(Context* c, unsigned size, Assembler::Address* a, - Assembler::Memory* b) -{ - assert(c, BytesPerWord == 8 or size == 4); // todo - - Assembler::Register tmp(c->client->acquireTemporary()); - moveAR(c, size, a, &tmp); - moveRM(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); -} - -void -moveMM(Context* c, unsigned size, Assembler::Memory* a, - Assembler::Memory* b) -{ - if (BytesPerWord == 8 or size <= 4) { - uint32_t mask; - if (BytesPerWord == 4 and size == 1) { - mask = (1 << rax) | (1 << rcx) | (1 << rdx) | (1 << rbx); - } else { - mask = ~static_cast(0); - } - - Assembler::Register tmp(c->client->acquireTemporary(mask)); - moveMR(c, size, a, &tmp); - moveRM(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); - } else { - Assembler::Register tmp(c->client->acquireTemporary(), - c->client->acquireTemporary()); - moveMR(c, size, a, &tmp); - moveRM(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); - c->client->releaseTemporary(tmp.high); - } -} - -void -move4To8MR(Context* c, unsigned, Assembler::Memory* a, Assembler::Register* b) -{ - if (BytesPerWord == 8) { - encode(c, 0x63, b->low, a, true); - } else { - assert(c, b->low == rax and b->high == rdx); - - moveMR(c, 4, a, b); - move4To8RR(c, 0, b, b); - } -} - -void -moveZMR(Context* c, unsigned size, Assembler::Memory* a, - Assembler::Register* b) -{ - switch (size) { - case 2: - encode2(c, 0x0fb7, b->low, a, true); - break; - - default: abort(c); // todo - } -} - -void -moveZRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - switch (size) { - case 2: - rex(c); - c->code.append(0x0f); - c->code.append(0xb7); - c->code.append(0xc0 | (b->low << 3) | a->low); - break; - - default: abort(c); // todo - } -} - -void -swapRR(Context* c, unsigned, Assembler::Register* a, Assembler::Register* b) -{ - rex(c); - c->code.append(0x87); - c->code.append(0xc0 | (b->low << 3) | a->low); -} - -void -addCM(Context* c, unsigned size UNUSED, Assembler::Constant* a, - Assembler::Memory* b) -{ - assert(c, BytesPerWord == 8 or size == 4); // todo - - int64_t v = a->value->value(); - unsigned i = (isInt8(v) ? 0x83 : 0x81); - - encode(c, i, 0, b, true); - if (isInt8(v)) { - c->code.append(v); - } else if (isInt32(v)) { - c->code.append4(v); - } else { - abort(c); - } -} - -void -addRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b); - -void -addCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - int64_t v = a->value->value(); - if (v) { - if (BytesPerWord == 4 and size == 8) { - ResolvedPromise high((v >> 32) & 0xFFFFFFFF); - Assembler::Constant ah(&high); - - ResolvedPromise low(v & 0xFFFFFFFF); - Assembler::Constant al(&low); - - Assembler::Register bh(b->high); - - addCR(c, 4, &al, b); - addCarryCR(c, 4, &ah, &bh); - } else { - if (size == 8) rex(c); - if (isInt8(v)) { - c->code.append(0x83); - c->code.append(0xc0 | b->low); - c->code.append(v); - } else if (isInt32(v)) { - c->code.append(0x81); - c->code.append(0xc0 | b->low); - c->code.append4(v); - } else { - Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - addRR(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); - } - } - } -} - -void -subtractBorrowCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - int64_t v = a->value->value(); - if (isInt8(v)) { - c->code.append(0x83); - c->code.append(0xd8 | b->low); - c->code.append(v); - } else { - abort(c); - } -} - -void -subtractRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b); - -void -subtractCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - int64_t v = a->value->value(); - if (v) { - if (BytesPerWord == 4 and size == 8) { - ResolvedPromise high((v >> 32) & 0xFFFFFFFF); - Assembler::Constant ah(&high); - - ResolvedPromise low(v & 0xFFFFFFFF); - Assembler::Constant al(&low); - - Assembler::Register bh(b->high); - - subtractCR(c, 4, &al, b); - subtractBorrowCR(c, 4, &ah, &bh); - } else { - if (size == 8) rex(c); - if (isInt8(v)) { - c->code.append(0x83); - c->code.append(0xe8 | b->low); - c->code.append(v); - } else if (isInt32(v)) { - c->code.append(0x81); - c->code.append(0xe8 | b->low); - c->code.append4(v); - } else { - Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - subtractRR(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); - } - } - } -} - -void -subtractBorrowRR(Context* c, unsigned size UNUSED, Assembler::Register* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - if (size == 8) rex(c); - c->code.append(0x19); - c->code.append(0xc0 | (a->low << 3) | b->low); -} - -void -subtractRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Register ah(a->high); - Assembler::Register bh(b->high); - - subtractRR(c, 4, a, b); - subtractBorrowRR(c, 4, &ah, &bh); - } else { - if (size == 8) rex(c); - c->code.append(0x29); - c->code.append(0xc0 | (a->low << 3) | b->low); - } -} - -void -addCarryRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - if (size == 8) rex(c); - c->code.append(0x11); - c->code.append(0xc0 | (a->low << 3) | b->low); -} - -void -addRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Register ah(a->high); - Assembler::Register bh(b->high); - - addRR(c, 4, a, b); - addCarryRR(c, 4, &ah, &bh); - } else { - if (size == 8) rex(c); - c->code.append(0x01); - c->code.append(0xc0 | (a->low << 3) | b->low); - } -} - -void -addRM(Context* c, unsigned size UNUSED, Assembler::Register* a, - Assembler::Memory* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - encode(c, 0x01, a->low, b, true); -} - -void -multiplyRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - if (BytesPerWord == 4 and size == 8) { - assert(c, b->high == rdx); - assert(c, b->low != rax); - assert(c, a->low != rax); - assert(c, a->high != rax); - - c->client->save(rax); - - Assembler::Register axdx(rax, rdx); - Assembler::Register ah(a->high); - Assembler::Register bh(b->high); - - moveRR(c, 4, b, &axdx); - multiplyRR(c, 4, &ah, b); - multiplyRR(c, 4, a, &bh); - addRR(c, 4, &bh, b); - - // mul a->low,%eax%edx - c->code.append(0xf7); - c->code.append(0xe0 | a->low); - - addRR(c, 4, b, &bh); - moveRR(c, 4, &axdx, b); - - c->client->restore(rax); - } else { - if (size == 8) rex(c); - c->code.append(0x0f); - c->code.append(0xaf); - c->code.append(0xc0 | (b->low << 3) | a->low); - } -} - -void -multiplyCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - if (BytesPerWord == 4 and size == 8) { - const uint32_t mask = ~((1 << rax) | (1 << rdx)); - Assembler::Register tmp(c->client->acquireTemporary(mask), - c->client->acquireTemporary(mask)); - - moveCR(c, size, a, &tmp); - multiplyRR(c, size, &tmp, b); - - c->client->releaseTemporary(tmp.low); - c->client->releaseTemporary(tmp.high); - } else { - int64_t v = a->value->value(); - if (v != 1) { - if (isInt32(v)) { - if (size == 8) rex(c); - if (isInt8(v)) { - c->code.append(0x6b); - c->code.append(0xc0 | (b->low << 3) | b->low); - c->code.append(v); - } else { - c->code.append(0x69); - c->code.append(0xc0 | (b->low << 3) | b->low); - c->code.append4(v); - } - } else { - Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - multiplyRR(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); - } - } - } -} - -void -divideRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b UNUSED) -{ - assert(c, BytesPerWord == 8 or size == 4); - - assert(c, b->low == rax); - assert(c, a->low != rdx); - - c->client->save(rdx); - - if (size == 8) rex(c); - c->code.append(0x99); // cdq - if (size == 8) rex(c); - c->code.append(0xf7); - c->code.append(0xf8 | a->low); - - c->client->restore(rdx); -} - -void -divideCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - const uint32_t mask = ~((1 << rax) | (1 << rdx)); - Assembler::Register tmp(c->client->acquireTemporary(mask)); - moveCR(c, size, a, &tmp); - divideRR(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); -} - -void -remainderRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - assert(c, b->low == rax); - assert(c, a->low != rdx); - - c->client->save(rdx); - - if (size == 8) rex(c); - c->code.append(0x99); // cdq - if (size == 8) rex(c); - c->code.append(0xf7); - c->code.append(0xf8 | a->low); - - Assembler::Register dx(rdx); - moveRR(c, BytesPerWord, &dx, b); - - c->client->restore(rdx); -} - -void -remainderCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - const uint32_t mask = ~((1 << rax) | (1 << rdx)); - Assembler::Register tmp(c->client->acquireTemporary(mask)); - moveCR(c, size, a, &tmp); - remainderRR(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); -} - -void -andRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Register ah(a->high); - Assembler::Register bh(b->high); - - andRR(c, 4, a, b); - andRR(c, 4, &ah, &bh); - } else { - if (size == 8) rex(c); - c->code.append(0x21); - c->code.append(0xc0 | (a->low << 3) | b->low); - } -} - -void -andCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - int64_t v = a->value->value(); - - if (BytesPerWord == 4 and size == 8) { - ResolvedPromise high((v >> 32) & 0xFFFFFFFF); - Assembler::Constant ah(&high); - - ResolvedPromise low(v & 0xFFFFFFFF); - Assembler::Constant al(&low); - - Assembler::Register bh(b->high); - - andCR(c, 4, &al, b); - andCR(c, 4, &ah, &bh); - } else { - if (isInt32(v)) { - if (size == 8) rex(c); - if (isInt8(v)) { - c->code.append(0x83); - c->code.append(0xe0 | b->low); - c->code.append(v); - } else { - c->code.append(0x81); - c->code.append(0xe0 | b->low); - c->code.append4(v); - } - } else { - Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - andRR(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); - } - } -} - -void -andCM(Context* c, unsigned size UNUSED, Assembler::Constant* a, - Assembler::Memory* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - int64_t v = a->value->value(); - - encode(c, isInt8(a->value->value()) ? 0x83 : 0x81, 5, b, true); - if (isInt8(v)) { - c->code.append(v); - } else if (isInt32(v)) { - c->code.append4(v); - } else { - abort(c); - } -} - -void -orRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Register ah(a->high); - Assembler::Register bh(b->high); - - orRR(c, 4, a, b); - orRR(c, 4, &ah, &bh); - } else { - if (size == 8) rex(c); - c->code.append(0x09); - c->code.append(0xc0 | (a->low << 3) | b->low); - } -} - -void -orCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - int64_t v = a->value->value(); - if (v) { - if (BytesPerWord == 4 and size == 8) { - ResolvedPromise high((v >> 32) & 0xFFFFFFFF); - Assembler::Constant ah(&high); - - ResolvedPromise low(v & 0xFFFFFFFF); - Assembler::Constant al(&low); - - Assembler::Register bh(b->high); - - orCR(c, 4, &al, b); - orCR(c, 4, &ah, &bh); - } else { - if (isInt32(v)) { - if (size == 8) rex(c); - if (isInt8(v)) { - c->code.append(0x83); - c->code.append(0xc8 | b->low); - c->code.append(v); - } else { - c->code.append(0x81); - c->code.append(0xc8 | b->low); - c->code.append4(v); - } - } else { - Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - orRR(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); - } - } - } -} - -void -xorRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Register ah(a->high); - Assembler::Register bh(b->high); - - xorRR(c, 4, a, b); - xorRR(c, 4, &ah, &bh); - } else { - if (size == 8) rex(c); - c->code.append(0x31); - c->code.append(0xc0 | (a->low << 3) | b->low); - } -} - -void -xorCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - int64_t v = a->value->value(); - if (v) { - if (BytesPerWord == 4 and size == 8) { - ResolvedPromise high((v >> 32) & 0xFFFFFFFF); - Assembler::Constant ah(&high); - - ResolvedPromise low(v & 0xFFFFFFFF); - Assembler::Constant al(&low); - - Assembler::Register bh(b->high); - - xorCR(c, 4, &al, b); - xorCR(c, 4, &ah, &bh); - } else { - if (isInt32(v)) { - if (size == 8) rex(c); - if (isInt8(v)) { - c->code.append(0x83); - c->code.append(0xf0 | b->low); - c->code.append(v); - } else { - c->code.append(0x81); - c->code.append(0xf0 | b->low); - c->code.append4(v); - } - } else { - Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - xorRR(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); - } - } - } -} - -void -doShift(Context* c, void (*shift) - (Context*, unsigned, Assembler::Register*, Assembler::Register*), - int type, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - int64_t v = a->value->value(); - - if (BytesPerWord == 4 and size == 8) { - c->client->save(rcx); - - Assembler::Register cx(rcx); - moveCR(c, 4, a, &cx); - shift(c, size, &cx, b); - - c->client->restore(rcx); - } else { - if (size == 8) rex(c); - if (v == 1) { - c->code.append(0xd1); - c->code.append(type | b->low); - } else if (isInt8(v)) { - c->code.append(0xc1); - c->code.append(type | b->low); - c->code.append(v); - } else { - abort(c); - } - } -} - -void -compareCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b); - -void -shiftLeftRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - assert(c, a->low == rcx); - - if (BytesPerWord == 4 and size == 8) { - // shld - c->code.append(0x0f); - c->code.append(0xa5); - c->code.append(0xc0 | (b->low << 3) | b->high); - - // shl - c->code.append(0xd3); - c->code.append(0xe0 | b->low); - - ResolvedPromise promise(32); - Assembler::Constant constant(&promise); - compareCR(c, 4, &constant, a); - - c->code.append(0x0f); - c->code.append(0x8c); // jl - c->code.append4(2 + 2); - - Assembler::Register bh(b->high); - moveRR(c, 4, b, &bh); // 2 bytes - xorRR(c, 4, b, b); // 2 bytes - } else { - if (size == 8) rex(c); - c->code.append(0xd3); - c->code.append(0xe0 | b->low); - } -} - -void -shiftLeftCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) +inline unsigned +index(UnaryOperation operation, OperandType operand) { - doShift(c, shiftLeftRR, 0xe0, size, a, b); + return operation + (UnaryOperationCount * operand); } -void -shiftRightRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - assert(c, a->low == rcx); - - if (BytesPerWord == 4 and size == 8) { - // shrd - c->code.append(0x0f); - c->code.append(0xad); - c->code.append(0xc0 | (b->high << 3) | b->low); - - // sar - c->code.append(0xd3); - c->code.append(0xf8 | b->high); - - ResolvedPromise promise(32); - Assembler::Constant constant(&promise); - compareCR(c, 4, &constant, a); - - c->code.append(0x0f); - c->code.append(0x8c); // jl - c->code.append4(2 + 3); - - Assembler::Register bh(b->high); - moveRR(c, 4, &bh, b); // 2 bytes - - // sar 31,high - c->code.append(0xc1); - c->code.append(0xf8 | b->high); - c->code.append(31); - } else { - if (size == 8) rex(c); - c->code.append(0xd3); - c->code.append(0xf8 | b->low); - } -} - -void -shiftRightCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - doShift(c, shiftRightRR, 0xf8, size, a, b); -} - -void -unsignedShiftRightRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - assert(c, a->low == rcx); - - if (BytesPerWord == 4 and size == 8) { - // shrd - c->code.append(0x0f); - c->code.append(0xad); - c->code.append(0xc0 | (b->high << 3) | b->low); - - // shr - c->code.append(0xd3); - c->code.append(0xe8 | b->high); - - ResolvedPromise promise(32); - Assembler::Constant constant(&promise); - compareCR(c, 4, &constant, a); - - c->code.append(0x0f); - c->code.append(0x8c); // jl - c->code.append4(2 + 2); - - Assembler::Register bh(b->high); - moveRR(c, 4, &bh, b); // 2 bytes - xorRR(c, 4, &bh, &bh); // 2 bytes - } else { - if (size == 8) rex(c); - c->code.append(0xd3); - c->code.append(0xe8 | b->low); - } -} - -void -unsignedShiftRightCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - doShift(c, unsignedShiftRightRR, 0xe8, size, a, b); -} - -void -compareRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - if (size == 8) rex(c); - c->code.append(0x39); - c->code.append(0xc0 | (a->low << 3) | b->low); -} - -void -compareAR(Context* c, unsigned size, Assembler::Address* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - Assembler::Register tmp(c->client->acquireTemporary()); - moveAR(c, size, a, &tmp); - compareRR(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); -} - -void -compareCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - int64_t v = a->value->value(); - - 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 { - Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - compareRR(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); - } -} - -void -compareCM(Context* c, unsigned size UNUSED, Assembler::Constant* a, - Assembler::Memory* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - int64_t v = a->value->value(); - - encode(c, isInt8(v) ? 0x83 : 0x81, 7, b, true); - - if (isInt8(v)) { - c->code.append(v); - } else if (isInt32(v)) { - c->code.append4(v); - } else { - abort(c); - } -} - -void -compareRM(Context* c, unsigned size, Assembler::Register* a, - Assembler::Memory* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - if (BytesPerWord == 8 and size == 4) { - move4To8RR(c, size, a, a); - } - encode(c, 0x39, a->low, b, true); -} - -void -compareAM(Context* c, unsigned size, Assembler::Address* a, - Assembler::Memory* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - Assembler::Register tmp(c->client->acquireTemporary()); - moveAR(c, size, a, &tmp); - compareRM(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); -} - -void -compareMR(Context* c, unsigned size, Assembler::Memory* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - if (BytesPerWord == 8 and size == 4) { - move4To8RR(c, size, b, b); - } - encode(c, 0x3b, b->low, a, true); -} - -void -compareMM(Context* c, unsigned size, Assembler::Memory* a, - Assembler::Memory* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - Assembler::Register tmp(c->client->acquireTemporary()); - moveMR(c, size, a, &tmp); - compareRM(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); -} - -void -compareRC(Context* c, unsigned size, Assembler::Register* a, - Assembler::Constant* b) +inline unsigned +index(BinaryOperation operation, + OperandType operand1, + OperandType operand2) { - assert(c, BytesPerWord == 8 or size == 4); - - Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, b, &tmp); - compareRR(c, size, a, &tmp); - c->client->releaseTemporary(tmp.low); + return operation + + (BinaryOperationCount * operand1) + + (BinaryOperationCount * OperandTypeCount * operand2); } -void -longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, - Assembler::Operand* bl, Assembler::Operand* bh, - BinaryOperationType compare, BinaryOperationType move) +inline unsigned +index(TernaryOperation operation, + OperandType operand1, + OperandType operand2, + OperandType operand3) { - ResolvedPromise negativePromise(-1); - Assembler::Constant negative(&negativePromise); - - ResolvedPromise zeroPromise(0); - Assembler::Constant zero(&zeroPromise); - - ResolvedPromise positivePromise(1); - Assembler::Constant positive(&positivePromise); - - if (BytesPerWord == 8) { - compare(c, 8, al, bl); - - 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); - - move(c, 4, &zero, bl); - - 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); - - move(c, 4, &negative, bl); - - 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); - - move(c, 4, &positive, bl); - - 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 { - compare(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); - - compare(c, 4, al, bl); - - 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); - - move(c, 4, &zero, bl); - - 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); - - move(c, 4, &negative, bl); - - 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); - - move(c, 4, &positive, bl); - - 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); - } + return operation + + (TernaryOperationCount * operand1) + + (TernaryOperationCount * OperandTypeCount * operand2) + + (TernaryOperationCount * OperandTypeCount * OperandTypeCount * operand3); } void -longCompareCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, - Assembler::Register* b) +populateTables(ArchitectureContext*) { - assert(c, size == 8); - - int64_t v = a->value->value(); - - ResolvedPromise low(v & ~static_cast(0)); - Assembler::Constant al(&low); - - ResolvedPromise high((v >> 32) & ~static_cast(0)); - Assembler::Constant ah(&high); - - Assembler::Register bh(b->high); - - longCompare(c, &al, &ah, b, &bh, CAST2(compareCR), CAST2(moveCR)); -} - -void -longCompareRR(Context* c, unsigned size UNUSED, Assembler::Register* a, - Assembler::Register* b) -{ - assert(c, size == 8); - - Assembler::Register ah(a->high); - Assembler::Register bh(b->high); - - longCompare(c, a, &ah, b, &bh, CAST2(compareRR), CAST2(moveCR)); -} - -void -populateTables() -{ - Operations[Return] = return_; - - const int Constant = ConstantOperand; - const int Address = AddressOperand; - const int Register = RegisterOperand; - const int Memory = MemoryOperand; - - UnaryOperations[INDEX1(Call, Constant)] = CAST1(callC); - UnaryOperations[INDEX1(Call, Register)] = CAST1(callR); - UnaryOperations[INDEX1(Call, Memory)] = CAST1(callM); - - UnaryOperations[INDEX1(LongCall, Constant)] = CAST1(longCallC); - - UnaryOperations[INDEX1(AlignedCall, Constant)] = CAST1(alignedCallC); - - UnaryOperations[INDEX1(Jump, Constant)] = CAST1(jumpC); - UnaryOperations[INDEX1(Jump, Register)] = CAST1(jumpR); - UnaryOperations[INDEX1(Jump, Memory)] = CAST1(jumpM); - - UnaryOperations[INDEX1(LongJump, Constant)] = CAST1(longJumpC); - - UnaryOperations[INDEX1(JumpIfEqual, Constant)] = CAST1(jumpIfEqualC); - UnaryOperations[INDEX1(JumpIfNotEqual, Constant)] = CAST1(jumpIfNotEqualC); - UnaryOperations[INDEX1(JumpIfGreater, Constant)] = CAST1(jumpIfGreaterC); - UnaryOperations[INDEX1(JumpIfGreaterOrEqual, Constant)] - = CAST1(jumpIfGreaterOrEqualC); - UnaryOperations[INDEX1(JumpIfLess, Constant)] = CAST1(jumpIfLessC); - UnaryOperations[INDEX1(JumpIfLessOrEqual, Constant)] - = CAST1(jumpIfLessOrEqualC); - - UnaryOperations[INDEX1(Push, Constant)] = CAST1(pushC); - UnaryOperations[INDEX1(Push, Address)] = CAST1(pushA); - UnaryOperations[INDEX1(Push, Register)] = CAST1(pushR); - UnaryOperations[INDEX1(Push, Memory)] = CAST1(pushM); - - UnaryOperations[INDEX1(Pop, Register)] = CAST1(popR); - UnaryOperations[INDEX1(Pop, Memory)] = CAST1(popM); - - UnaryOperations[INDEX1(Negate, Register)] = CAST1(negateR); - - BinaryOperations[INDEX2(LoadAddress, Memory, Register)] = CAST2(leaMR); - - BinaryOperations[INDEX2(Move, Constant, Register)] = CAST2(moveCR); - BinaryOperations[INDEX2(Move, Constant, Memory)] = CAST2(moveCM); - BinaryOperations[INDEX2(Move, Register, Memory)] = CAST2(moveRM); - BinaryOperations[INDEX2(Move, Register, Register)] = CAST2(moveRR); - BinaryOperations[INDEX2(Move, Memory, Register)] = CAST2(moveMR); - BinaryOperations[INDEX2(Move, Address, Register)] = CAST2(moveAR); - BinaryOperations[INDEX2(Move, Address, Memory)] = CAST2(moveAM); - BinaryOperations[INDEX2(Move, Memory, Memory)] = CAST2(moveMM); - - BinaryOperations[INDEX2(Move4To8, Constant, Register)] = CAST2(move4To8CR); - BinaryOperations[INDEX2(Move4To8, Register, Register)] = CAST2(move4To8RR); - BinaryOperations[INDEX2(Move4To8, Memory, Register)] = CAST2(move4To8MR); - - BinaryOperations[INDEX2(MoveZ, Memory, Register)] = CAST2(moveZMR); - BinaryOperations[INDEX2(MoveZ, Register, Register)] = CAST2(moveZRR); - - BinaryOperations[INDEX2(Swap, Register, Register)] = CAST2(swapRR); - - BinaryOperations[INDEX2(Add, Constant, Register)] = CAST2(addCR); - BinaryOperations[INDEX2(Add, Register, Register)] = CAST2(addRR); - BinaryOperations[INDEX2(Add, Register, Memory)] = CAST2(addRM); - BinaryOperations[INDEX2(Add, Constant, Memory)] = CAST2(addCM); - - BinaryOperations[INDEX2(Multiply, Register, Register)] = CAST2(multiplyRR); - BinaryOperations[INDEX2(Multiply, Constant, Register)] = CAST2(multiplyCR); - - BinaryOperations[INDEX2(Divide, Register, Register)] = CAST2(divideRR); - BinaryOperations[INDEX2(Divide, Constant, Register)] = CAST2(divideCR); - - BinaryOperations[INDEX2(Remainder, Constant, Register)] = CAST2(remainderCR); - BinaryOperations[INDEX2(Remainder, Register, Register)] = CAST2(remainderRR); - - BinaryOperations[INDEX2(And, Register, Register)] = CAST2(andRR); - BinaryOperations[INDEX2(And, Constant, Register)] = CAST2(andCR); - BinaryOperations[INDEX2(And, Constant, Memory)] = CAST2(andCM); - - BinaryOperations[INDEX2(Or, Register, Register)] = CAST2(orRR); - BinaryOperations[INDEX2(Or, Constant, Register)] = CAST2(orCR); - - BinaryOperations[INDEX2(Xor, Register, Register)] = CAST2(xorRR); - BinaryOperations[INDEX2(Xor, Constant, Register)] = CAST2(xorCR); - - BinaryOperations[INDEX2(ShiftLeft, Register, Register)] = CAST2(shiftLeftRR); - BinaryOperations[INDEX2(ShiftLeft, Constant, Register)] = CAST2(shiftLeftCR); - - BinaryOperations[INDEX2(ShiftRight, Register, Register)] - = CAST2(shiftRightRR); - BinaryOperations[INDEX2(ShiftRight, Constant, Register)] - = CAST2(shiftRightCR); - - BinaryOperations[INDEX2(UnsignedShiftRight, Register, Register)] - = CAST2(unsignedShiftRightRR); - BinaryOperations[INDEX2(UnsignedShiftRight, Constant, Register)] - = CAST2(unsignedShiftRightCR); - - BinaryOperations[INDEX2(Subtract, Constant, Register)] = CAST2(subtractCR); - BinaryOperations[INDEX2(Subtract, Register, Register)] = CAST2(subtractRR); + // todo - BinaryOperations[INDEX2(LongCompare, Constant, Register)] - = CAST2(longCompareCR); - BinaryOperations[INDEX2(LongCompare, Register, Register)] - = CAST2(longCompareRR); +// const int Constant = ConstantOperand; +// const int Address = AddressOperand; +// const int Register = RegisterOperand; +// const int Memory = MemoryOperand; - BinaryOperations[INDEX2(Compare, Constant, Register)] = CAST2(compareCR); - BinaryOperations[INDEX2(Compare, Register, Constant)] = CAST2(compareRC); - BinaryOperations[INDEX2(Compare, Register, Register)] = CAST2(compareRR); - BinaryOperations[INDEX2(Compare, Address, Register)] = CAST2(compareAR); - BinaryOperations[INDEX2(Compare, Address, Memory)] = CAST2(compareAM); - BinaryOperations[INDEX2(Compare, Register, Memory)] = CAST2(compareRM); - BinaryOperations[INDEX2(Compare, Memory, Register)] = CAST2(compareMR); - BinaryOperations[INDEX2(Compare, Constant, Memory)] = CAST2(compareCM); - BinaryOperations[INDEX2(Compare, Memory, Memory)] = CAST2(compareMM); +// #define CAST1(x) reinterpret_cast(x) +// #define CAST2(x) reinterpret_cast(x) +// #define CAST3(x) reinterpret_cast(x) } -class MyAssembler: public Assembler { +class MyArchitecture: public Assembler::Architecture { public: - MyAssembler(System* s, Allocator* a, Zone* zone): c(s, a, zone) { - static bool populated = false; - if (not populated) { - populated = true; - populateTables(); - } - } - - virtual void setClient(Client* client) { - assert(&c, c.client == 0); - c.client = client; + MyArchitecture(System* system): c(system), referenceCount(0) { + populateTables(&c); } virtual unsigned registerCount() { return 8;//BytesPerWord == 4 ? 8 : 16; } - virtual int base() { - return rbp; - } - virtual int stack() { return rsp; } @@ -2040,7 +387,7 @@ class MyAssembler: public Assembler { virtual int returnHigh() { return (BytesPerWord == 4 ? rdx : NoRegister); - } + } virtual unsigned argumentRegisterCount() { return (BytesPerWord == 4 ? 0 : 6); @@ -2067,32 +414,57 @@ class MyAssembler: public Assembler { } } - virtual unsigned stackPadding(unsigned footprint) { -#if (defined __APPLE__) || (defined __x86_64__) - const unsigned alignment = 16 / BytesPerWord; - return (ceiling(footprint, alignment) * alignment) - footprint; -#else - return 0; -#endif + virtual void updateCall(void* returnAddress, void* newTarget) { + uint8_t* instruction = static_cast(returnAddress) - 5; + assert(&c, *instruction == 0xE8); + assert(&c, reinterpret_cast(instruction + 1) % 4 == 0); + + int32_t v = static_cast(newTarget) + - static_cast(returnAddress); + memcpy(instruction + 1, &v, 4); } - virtual void plan(UnaryOperation op, unsigned size, uint8_t* typeMask, - uint64_t* registerMask, bool* thunk) + virtual unsigned alignFrameSize(unsigned sizeInWords) { + const unsigned alignment = 16 / BytesPerWord; + return (ceiling(sizeInWords + 2, alignment) * alignment); + } + + virtual void* frameIp(void* stack) { + return *static_cast(stack); + } + + virtual unsigned frameHeaderSize() { + return 2; + } + + virtual unsigned frameFooterSize() { + return 0; + } + + virtual void nextFrame(void** stack, void** base) { + *stack = static_cast(*base) + 1; + *base = *static_cast(*base); + } + + virtual void* popReturnAddress(void* stack) { + return static_cast(stack) + 1; + } + + virtual void plan + (UnaryOperation, + unsigned, uint8_t* aTypeMask, uint64_t* aRegisterMask, + bool* thunk) { - if (op == Negate and BytesPerWord == 4 and size == 8) { - *typeMask = 1 << RegisterOperand; - *registerMask = (static_cast(1) << (rdx + 32)) - | (static_cast(1) << rax); - } else { - *typeMask = (1 << RegisterOperand) | (1 << MemoryOperand); - *registerMask = ~static_cast(0); - } + *aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand); + *aRegisterMask = ~static_cast(0); *thunk = false; } - virtual void plan(BinaryOperation op, unsigned size, uint8_t* aTypeMask, - uint64_t* aRegisterMask, uint8_t* bTypeMask, - uint64_t* bRegisterMask, bool* thunk) + virtual void plan + (BinaryOperation op, + unsigned aSize, uint8_t* aTypeMask, uint64_t* aRegisterMask, + unsigned bSize, uint8_t* bTypeMask, uint64_t* bRegisterMask, + bool* thunk) { *aTypeMask = ~0; *aRegisterMask = ~static_cast(0); @@ -2104,7 +476,7 @@ class MyAssembler: public Assembler { switch (op) { case Compare: - if (BytesPerWord == 8 and size != 8) { + if (BytesPerWord == 8 and aSize != 8) { *aTypeMask = ~(1 << MemoryOperand); *bTypeMask = ~(1 << MemoryOperand); } else { @@ -2113,81 +485,95 @@ class MyAssembler: public Assembler { break; case Move: - if (BytesPerWord == 4 and size == 1) { - const uint32_t mask - = (1 << rax) | (1 << rcx) | (1 << rdx) | (1 << rbx); - *aRegisterMask = (static_cast(mask) << 32) | mask; - *bRegisterMask = (static_cast(mask) << 32) | mask; - } - break; - - case Move4To8: if (BytesPerWord == 4) { - const uint32_t mask = ~((1 << rax) | (1 << rdx)); - *aRegisterMask = (static_cast(mask) << 32) | mask; - *bRegisterMask = (static_cast(1) << (rdx + 32)) - | (static_cast(1) << rax); + if (aSize == 4 and bSize == 8) { + const uint32_t mask = ~((1 << rax) | (1 << rdx)); + *aRegisterMask = (static_cast(mask) << 32) | mask; + *bRegisterMask = (static_cast(1) << (rdx + 32)) + | (static_cast(1) << rax); + } else if (aSize == 1) { + const uint32_t mask + = (1 << rax) | (1 << rcx) | (1 << rdx) | (1 << rbx); + *aRegisterMask = (static_cast(mask) << 32) | mask; + *bRegisterMask = (static_cast(mask) << 32) | mask; + } } break; - case Multiply: - if (BytesPerWord == 4 and size == 8) { - const uint32_t mask = ~((1 << rax) | (1 << rdx)); - *aRegisterMask = (static_cast(mask) << 32) | mask; - *bRegisterMask = (static_cast(1) << (rdx + 32)) | mask; - } - break; - - case Divide: - if (BytesPerWord == 4 and size == 8) { - *bTypeMask = ~0; - *thunk = true; - } else { - *aRegisterMask = ~((1 << rax) | (1 << rdx)); - *bRegisterMask = 1 << rax; - } - break; - - case Remainder: - if (BytesPerWord == 4 and size == 8) { - *bTypeMask = ~0; - *thunk = true; - } else { - *aRegisterMask = ~((1 << rax) | (1 << rdx)); - *bRegisterMask = 1 << rax; - } - break; - - case ShiftLeft: - case ShiftRight: - case UnsignedShiftRight: { - *aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand); - *aRegisterMask = (~static_cast(0) << 32) - | (static_cast(1) << rcx); - const uint32_t mask = ~(1 << rcx); - *bRegisterMask = (static_cast(mask) << 32) | mask; - } break; - default: break; } } + virtual void plan + (TernaryOperation, + unsigned, uint8_t* aTypeMask, uint64_t* aRegisterMask, + unsigned, uint8_t* bTypeMask, uint64_t* bRegisterMask, + unsigned, uint8_t* cTypeMask, uint64_t* cRegisterMask, + bool* thunk) + { + *aTypeMask = ~0; + *aRegisterMask = ~static_cast(0); + + *bTypeMask = ~0; + *bRegisterMask = ~static_cast(0); + + *cTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand); + *cRegisterMask = ~static_cast(0); + + *thunk = false; + } + + virtual void acquire() { + ++ referenceCount; + } + + virtual void release() { + if (-- referenceCount == 0) { + c.s->free(this); + } + } + + ArchitectureContext c; + unsigned referenceCount; +}; + +class MyAssembler: public Assembler { + public: + MyAssembler(System* s, Allocator* a, Zone* zone, ArchitectureContext* ac): + c(s, a, zone), ac(ac) + { } + + virtual void setClient(Client* client) { + assert(&c, c.client == 0); + c.client = client; + } + virtual void apply(Operation op) { - Operations[op](&c); + ac->operations[op](&c); } - virtual void apply(UnaryOperation op, unsigned size, - OperandType type, Operand* operand) + virtual void apply(UnaryOperation op, + unsigned aSize, OperandType aType, Operand* aOperand) { - UnaryOperations[INDEX1(op, type)](&c, size, operand); + ac->unaryOperations[index(op, aType)](&c, aSize, aOperand); } - virtual void apply(BinaryOperation op, unsigned size, - OperandType aType, Operand* a, - OperandType bType, Operand* b) + virtual void apply(BinaryOperation op, + unsigned aSize, OperandType aType, Operand* aOperand, + unsigned bSize, OperandType bType, Operand* bOperand) { - BinaryOperations[INDEX2(op, aType, bType)](&c, size, a, b); + ac->binaryOperations[index(op, aType, bType)] + (&c, aSize, aOperand, bSize, bOperand); + } + + virtual void apply(TernaryOperation op, + unsigned aSize, OperandType aType, Operand* aOperand, + unsigned bSize, OperandType bType, Operand* bOperand, + unsigned cSize, OperandType cType, Operand* cOperand) + { + ac->ternaryOperations[index(op, aType, bType, cType)] + (&c, aSize, aOperand, bSize, bOperand, cSize, cOperand); } virtual void writeTo(uint8_t* dst) { @@ -2203,32 +589,32 @@ class MyAssembler: public Assembler { return c.code.length(); } - virtual void updateCall(void* returnAddress, void* newTarget) { - uint8_t* instruction = static_cast(returnAddress) - 5; - assert(&c, *instruction == 0xE8); - assert(&c, reinterpret_cast(instruction + 1) % 4 == 0); - - int32_t v = static_cast(newTarget) - - static_cast(returnAddress); - memcpy(instruction + 1, &v, 4); - } - virtual void dispose() { c.code.dispose(); } Context c; + ArchitectureContext* ac; }; } // namespace namespace vm { -Assembler* -makeAssembler(System* system, Allocator* allocator, Zone* zone) +Assembler::Architecture* +makeArchitecture(System* system) { - return new (zone->allocate(sizeof(MyAssembler))) - MyAssembler(system, allocator, zone); + return new (allocate(system, sizeof(MyArchitecture))) MyArchitecture(system); } +Assembler* +makeAssembler(System* system, Allocator* allocator, Zone* zone, + Assembler::Architecture* architecture) +{ + return new (zone->allocate(sizeof(MyAssembler))) + MyAssembler(system, allocator, zone, + &(static_cast(architecture)->c)); +} + + } // namespace vm