diff --git a/src/assembler.h b/src/assembler.h index 01c84edbaf..35c58afb5b 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -137,7 +137,7 @@ class Assembler { public: virtual ~Client() { } - virtual int acquireTemporary() = 0; + virtual int acquireTemporary(int r = NoRegister) = 0; virtual void releaseTemporary(int r) = 0; }; diff --git a/src/compiler.cpp b/src/compiler.cpp index f57570e5e2..35abe02680 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -1512,8 +1512,13 @@ class Client: public Assembler::Client { public: Client(Context* c): c(c) { } - virtual int acquireTemporary() { - int r = freeRegisterExcept(c, NoRegister, false); + virtual int acquireTemporary(int r) { + if (r == NoRegister) { + r = freeRegisterExcept(c, NoRegister, false); + } else { + expect(c, not c->registers[r].reserved); + expect(c, c->registers[r].operand == 0); + } c->registers[r].reserved = true; return r; } diff --git a/src/x86.cpp b/src/x86.cpp index 1caa4b5512..7a435f9ef2 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -528,6 +528,25 @@ moveCM(Context* c, unsigned size UNUSED, Assembler::Constant* a, c->code.append4(a->value->value()); } +void +moveRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b) +{ + if (BytesPerWord == 4 and size == 8) { + Assembler::Register ah(a->low); + Assembler::Register bh(b->low); + + moveRR(c, 4, a, b); + moveRR(c, 4, &ah, &bh); + } else { + assert(c, BytesPerWord == 8 or size == 4); // todo + + rex(c); + c->code.append(0x89); + c->code.append(0xc0 | (a->low << 3) | b->low); + } +} + void moveRM(Context* c, unsigned size, Assembler::Register* a, Assembler::Memory* b) { @@ -540,24 +559,36 @@ moveRM(Context* c, unsigned size, Assembler::Register* a, Assembler::Memory* b) } else if (BytesPerWord == 8 and size == 4) { encode(c, 0x89, a->low, b, false); } else { - encode(c, 0x89, a->low, b, true); - } -} + 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 { + if (a->low > rbx) { + Assembler::Register ax(c->client->acquireTemporary(rax)); + moveRR(c, BytesPerWord, a, &ax); + moveRM(c, 1, &ax, b); + c->client->releaseTemporary(ax.low); + } else { + encode(c, 0x88, a->low, b, false); + } + } + break; -void -moveRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Register ah(a->low); - Assembler::Register bh(b->low); + case 2: + encode2(c, 0x6689, a->low, b, false); + break; - moveRR(c, 4, a, b); - moveRR(c, 4, &ah, &bh); - } else { - rex(c); - c->code.append(0x89); - c->code.append(0xc0 | (a->low << 3) | b->low); + case BytesPerWord: + encode(c, 0x89, a->low, b, true); + break; + + default: abort(c); + } } }