diff --git a/src/assembler.h b/src/assembler.h index 117d7d3618..01c84edbaf 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -133,8 +133,18 @@ class Assembler { TraceHandler* traceHandler; }; + class Client { + public: + virtual ~Client() { } + + virtual int acquireTemporary() = 0; + virtual void releaseTemporary(int r) = 0; + }; + virtual ~Assembler() { } + virtual void setClient(Client* client) = 0; + virtual unsigned registerCount() = 0; virtual int base() = 0; diff --git a/src/compiler.cpp b/src/compiler.cpp index 9a2f7cede6..5f27e33251 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -759,10 +759,11 @@ appendCall(Context* c, MyOperand* address, void* indirection, unsigned flags, } int -freeRegister(Context* c) +freeRegisterExcept(Context* c, int except) { for (int i = c->assembler->registerCount(); i >= 0; --i) { - if ((not c->registers[i].reserved) + if (i != except + and (not c->registers[i].reserved) and c->registers[i].operand == 0) { return i; @@ -770,7 +771,9 @@ freeRegister(Context* c) } for (int i = c->assembler->registerCount(); i >= 0; --i) { - if (not c->registers[i].reserved) { + if (i != except + and (not c->registers[i].reserved)) + { return i; } } @@ -778,11 +781,18 @@ freeRegister(Context* c) abort(c); } +inline int +freeRegister(Context* c) +{ + return freeRegisterExcept(c, NoRegister); +} + RegisterValue* freeRegister(Context* c, unsigned size) { if (BytesPerWord == 4 and size == 8) { - return register_(c, freeRegister(c), freeRegister(c)); + int low = freeRegister(c); + return register_(c, low, freeRegisterExcept(c, low)); } else { return register_(c, freeRegister(c)); } @@ -943,14 +953,6 @@ class MoveEvent: public Event { { dst->value = src->value; return; - } else if ((src->value->type(c) == Address - or src->value->type(c) == Memory) - and src->target->type(c) == Memory) - { - RegisterValue* tmp = freeRegister(c, size); - tmp->preserve(c, stack, 0); - apply(c, Move, size, src->value, tmp); - src->value = tmp; } src->value->release(c, src); @@ -1406,11 +1408,14 @@ compile(Context* c) } for (unsigned i = 0; i < c->logicalCodeLength; ++ i) { + LogicalInstruction* li = c->logicalCode + i; + li->machineOffset = a->length(); + fprintf(stderr, "compile ip %d\n", i); - for (Event* e = c->logicalCode[i].firstEvent; e; e = e->next) { + for (Event* e = li->firstEvent; e; e = e->next) { e->compile(c); - if (e == c->logicalCode[i].lastEvent) break; + if (e == li->lastEvent) break; for (CodePromise* p = e->promises; p; p = p->next) { p->offset = a->length(); @@ -1419,11 +1424,30 @@ compile(Context* c) } } +class Client: public Assembler::Client { + public: + Client(Context* c): c(c) { } + + virtual int acquireTemporary() { + int r = freeRegister(c); + c->registers[r].reserved = true; + return r; + } + + virtual void releaseTemporary(int r) { + c->registers[r].reserved = false; + } + + Context* c; +}; + class MyCompiler: public Compiler { public: MyCompiler(System* s, Assembler* assembler, Zone* zone): - c(s, assembler, zone) - { } + c(s, assembler, zone), client(&c) + { + assembler->setClient(&client); + } virtual void pushState() { ::pushState(&c); @@ -1795,6 +1819,7 @@ class MyCompiler: public Compiler { } Context c; + Client client; }; } // namespace diff --git a/src/x86.cpp b/src/x86.cpp index 79f4178359..9952fdb452 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -52,11 +52,12 @@ class Task; class Context { public: Context(System* s, Allocator* a, Zone* zone): - s(s), zone(zone), code(s, a, 1024), tasks(0), result(0) + s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0) { } System* s; Zone* zone; + Assembler::Client* client; Vector code; Task* tasks; uint8_t* result; @@ -341,6 +342,50 @@ jumpIfGreaterOrEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* a) conditional(c, 0x8d, a); } +void +jumpIfEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* a) +{ + assert(c, size == BytesPerWord); + + conditional(c, 0x84, a); +} + +void +moveCR(Context*, unsigned, Assembler::Constant*, Assembler::Register*); + +void +pushR(Context*, unsigned, Assembler::Register*); + +void +pushC(Context* c, unsigned size, Assembler::Constant* a) +{ + 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); + + pushC(c, 4, &ah); + pushC(c, 4, &al); + } else { + 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); + } + } +} + void pushR(Context* c, unsigned size, Assembler::Register* a) { @@ -531,6 +576,30 @@ moveAR(Context* c, unsigned size, Assembler::Address* a, 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) +{ + assert(c, BytesPerWord == 8 or size == 4); // todo + + Assembler::Register tmp(c->client->acquireTemporary()); + moveMR(c, size, a, &tmp); + moveRM(c, size, &tmp, b); + c->client->releaseTemporary(tmp.low); +} + void move4To8MR(Context* c, unsigned, Assembler::Memory* a, Assembler::Register* b) { @@ -564,7 +633,7 @@ addCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, void subtractCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, - Assembler::Register* b) + Assembler::Register* b) { assert(c, BytesPerWord == 8 or size == 4); // todo @@ -587,7 +656,7 @@ subtractCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, void addRR(Context* c, unsigned size UNUSED, Assembler::Register* a, - Assembler::Register* b) + Assembler::Register* b) { assert(c, BytesPerWord == 8 or size == 4); // todo @@ -611,17 +680,19 @@ andCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, { assert(c, BytesPerWord == 8 or size == 4); + int64_t v = a->value->value(); + rex(c); - if (isInt8(a->value->value())) { + if (isInt8(v)) { c->code.append(0x83); c->code.append(0xe0 | b->low); c->code.append(a->value->value()); - } else { - assert(c, isInt32(a->value->value())); - + } else if (isInt32(v)) { c->code.append(0x81); c->code.append(0xe0 | b->low); - c->code.append(a->value->value()); + c->code.append(v); + } else { + abort(c); } } @@ -631,11 +702,35 @@ andCM(Context* c, unsigned size UNUSED, Assembler::Constant* a, { 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(a->value->value())) { - c->code.append(a->value->value()); - } else if (isInt32(a->value->value())) { - c->code.append4(a->value->value()); + if (isInt8(v)) { + c->code.append(v); + } else if (isInt32(v)) { + c->code.append4(v); + } else { + abort(c); + } +} + +void +compareCR(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 (size == 8) rex(c); + if (isInt8(v)) { + c->code.append(0x83); + c->code.append(0xf8 | b->low); + c->code.append(v); + } else if (isInt32(v)) { + c->code.append(0x81); + c->code.append(0xf8 | b->low); + c->code.append4(v); } else { abort(c); } @@ -648,6 +743,7 @@ compareCM(Context* c, unsigned size UNUSED, Assembler::Constant* a, assert(c, BytesPerWord == 8 or size == 4); encode(c, isInt8(a->value->value()) ? 0x83 : 0x81, 7, b, true); + if (isInt8(a->value->value())) { c->code.append(a->value->value()); } else if (isInt32(a->value->value())) { @@ -672,7 +768,9 @@ populateTables() UnaryOperations[INDEX1(JumpIfGreaterOrEqual, Constant)] = CAST1(jumpIfGreaterOrEqualC); + UnaryOperations[INDEX1(JumpIfEqual, Constant)] = CAST1(jumpIfEqualC); + UnaryOperations[INDEX1(Push, Constant)] = CAST1(pushC); UnaryOperations[INDEX1(Push, Register)] = CAST1(pushR); UnaryOperations[INDEX1(Push, Memory)] = CAST1(pushM); @@ -687,6 +785,8 @@ populateTables() 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, Register, Register)] = CAST2(move4To8RR); BinaryOperations[INDEX2(Move4To8, Memory, Register)] = CAST2(move4To8MR); @@ -700,6 +800,7 @@ populateTables() BinaryOperations[INDEX2(Subtract, Constant, Register)] = CAST2(subtractCR); + BinaryOperations[INDEX2(Compare, Constant, Register)] = CAST2(compareCR); BinaryOperations[INDEX2(Compare, Constant, Memory)] = CAST2(compareCM); } @@ -713,6 +814,11 @@ class MyAssembler: public Assembler { } } + virtual void setClient(Client* client) { + assert(&c, c.client == 0); + c.client = client; + } + virtual unsigned registerCount() { return 8;//BytesPerWord == 4 ? 8 : 16; }