diff --git a/src/x86.cpp b/src/x86.cpp index 4d91ddbfa0..9ffb44c21c 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -49,21 +49,31 @@ isInt32(intptr_t v) } class Task; +class AlignmentPadding; + +unsigned +padding(AlignmentPadding* p, unsigned index, unsigned offset, unsigned limit); class MyBlock: public Assembler::Block { public: - MyBlock(unsigned offset): offset(offset), start(~0), size(0), next(0) { } + MyBlock(unsigned offset): + next(0), firstPadding(0), lastPadding(0), offset(offset), start(~0), + size(0) + { } virtual unsigned resolve(unsigned start, Assembler::Block* next) { this->start = start; this->next = static_cast(next); - return start + size; + + return start + size + padding(firstPadding, start, offset, ~0); } + MyBlock* next; + AlignmentPadding* firstPadding; + AlignmentPadding* lastPadding; unsigned offset; unsigned start; unsigned size; - MyBlock* next; }; class Context { @@ -239,6 +249,36 @@ appendImmediateTask(Context* c, Promise* promise, unsigned offset) (c->tasks, promise, offset); } +class AlignmentPadding { + public: + AlignmentPadding(Context* c): offset(c->code.length()), next(0) { + if (c->lastBlock->firstPadding) { + c->lastBlock->lastPadding->next = this; + } else { + c->lastBlock->firstPadding = this; + } + c->lastBlock->lastPadding = this; + } + + unsigned offset; + AlignmentPadding* next; +}; + +unsigned +padding(AlignmentPadding* p, unsigned index, unsigned offset, unsigned limit) +{ + unsigned padding = 0; + for (; p; p = p->next) { + if (p->offset <= limit) { + index += p->offset - offset; + while ((index + padding + 1) % 4) { + ++ padding; + } + } + } + return padding; +} + void encode(Context* c, uint8_t* instruction, unsigned length, int a, int b, int32_t displacement, int index, unsigned scale) @@ -417,6 +457,13 @@ callC(Context* c, unsigned size UNUSED, Assembler::Constant* a) unconditional(c, 0xe8, a); } +void +alignedCallC(Context* c, unsigned size, Assembler::Constant* a) +{ + new (c->zone->allocate(sizeof(AlignmentPadding))) AlignmentPadding(c); + callC(c, size, a); +} + void longCallC(Context* c, unsigned size, Assembler::Constant* a) { @@ -528,10 +575,8 @@ moveRR(Context* c, unsigned aSize, Assembler::Register* a, void moveMR(Context* c, unsigned aSize, Assembler::Memory* a, - unsigned bSize UNUSED, Assembler::Register* b) + unsigned bSize, Assembler::Register* b) { - assert(c, aSize == bSize); - switch (aSize) { case 1: encode2(c, 0x0fbe, b->low, a, true); @@ -543,16 +588,27 @@ moveMR(Context* c, unsigned aSize, Assembler::Memory* a, case 4: case 8: - if (BytesPerWord == 4 and aSize == 8) { - Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); - Assembler::Register bh(b->high); - - moveMR(c, 4, a, 4, b); - moveMR(c, 4, &ah, 4, &bh); - } else if (BytesPerWord == 8 and aSize == 4) { - encode(c, 0x63, b->low, a, true); + if (aSize == 4 and bSize == 8) { + if (BytesPerWord == 8) { + encode(c, 0x63, b->low, a, true); + } else { + assert(c, b->low == rax and b->high == rdx); + + moveMR(c, 4, a, 4, b); + moveRR(c, 4, b, 8, b); + } } else { - encode(c, 0x8b, b->low, a, true); + if (BytesPerWord == 4 and aSize == 8) { + Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); + Assembler::Register bh(b->high); + + moveMR(c, 4, a, 4, b); + moveMR(c, 4, &ah, 4, &bh); + } else if (BytesPerWord == 8 and aSize == 4) { + encode(c, 0x63, b->low, a, true); + } else { + encode(c, 0x8b, b->low, a, true); + } } break; @@ -603,6 +659,31 @@ moveRM(Context* c, unsigned aSize, Assembler::Register* a, } } +void +moveAR(Context* c, unsigned aSize, Assembler::Address* a, + unsigned bSize, Assembler::Register* b) +{ + assert(c, BytesPerWord == 8 or (aSize == 4 and bSize == 4)); + + Assembler::Constant constant(a->address); + Assembler::Memory memory(b->low, 0, -1, 0); + + moveCR(c, aSize, &constant, bSize, b); + moveMR(c, bSize, &memory, bSize, b); +} + +void +moveAM(Context* c, unsigned aSize, Assembler::Address* a, + unsigned bSize, Assembler::Memory* b) +{ + assert(c, BytesPerWord == 8 or (aSize == 4 and bSize == 4)); + + Assembler::Register tmp(c->client->acquireTemporary()); + moveAR(c, aSize, a, aSize, &tmp); + moveRM(c, aSize, &tmp, bSize, b); + c->client->releaseTemporary(tmp.low); +} + void moveCR(Context* c, unsigned aSize, Assembler::Constant* a, unsigned bSize UNUSED, Assembler::Register* b) @@ -634,6 +715,45 @@ moveCR(Context* c, unsigned aSize, Assembler::Constant* a, } } +void +moveCM(Context* c, unsigned aSize UNUSED, Assembler::Constant* a, + unsigned bSize, Assembler::Memory* b) +{ + int64_t v = a->value->value(); + + switch (bSize) { + 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, 4, b); + moveCM(c, 4, &ah, 4, &bh); + } break; + + default: abort(c); + } +} + void addCarryRR(Context* c, unsigned size, Assembler::Register* a, Assembler::Register* b) @@ -791,7 +911,7 @@ subtractBorrowRR(Context* c, unsigned size, Assembler::Register* a, void subtractRR(Context* c, unsigned aSize, Assembler::Register* a, - unsigned bSize, Assembler::Register* b) + unsigned bSize UNUSED, Assembler::Register* b) { assert(c, aSize == bSize); @@ -808,6 +928,65 @@ subtractRR(Context* c, unsigned aSize, Assembler::Register* a, } } +void +andRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b) +{ + assert(c, aSize == bSize); + + if (BytesPerWord == 4 and aSize == 8) { + Assembler::Register ah(a->high); + Assembler::Register bh(b->high); + + andRR(c, 4, a, 4, b); + andRR(c, 4, &ah, 4, &bh); + } else { + if (aSize == 8) rex(c); + c->code.append(0x21); + c->code.append(0xc0 | (a->low << 3) | b->low); + } +} + +void +andCR(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b) +{ + assert(c, aSize == bSize); + + int64_t v = a->value->value(); + + if (BytesPerWord == 4 and aSize == 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, 4, b); + andCR(c, 4, &ah, 4, &bh); + } else { + if (isInt32(v)) { + if (aSize == 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, aSize, a, aSize, &tmp); + andRR(c, aSize, &tmp, bSize, b); + c->client->releaseTemporary(tmp.low); + } + } +} + void populateTables(ArchitectureContext* c) { @@ -815,7 +994,7 @@ populateTables(ArchitectureContext* c) #define CAST2(x) reinterpret_cast(x) const OperandType C = ConstantOperand; - //const OperandType A = AddressOperand; + const OperandType A = AddressOperand; const OperandType R = RegisterOperand; const OperandType M = MemoryOperand; @@ -827,6 +1006,8 @@ populateTables(ArchitectureContext* c) uo[index(Call, C)] = CAST1(callC); + uo[index(AlignedCall, C)] = CAST1(alignedCallC); + uo[index(LongCall, C)] = CAST1(longCallC); uo[index(Jump, R)] = CAST1(jumpR); @@ -839,10 +1020,14 @@ populateTables(ArchitectureContext* c) bo[index(Move, C, R)] = CAST2(moveCR); bo[index(Move, M, R)] = CAST2(moveMR); bo[index(Move, R, M)] = CAST2(moveRM); + bo[index(Move, C, M)] = CAST2(moveCM); + bo[index(Move, A, M)] = CAST2(moveAM); bo[index(Add, C, R)] = CAST2(addCR); bo[index(Subtract, C, R)] = CAST2(subtractCR); + + bo[index(And, C, R)] = CAST2(andCR); } class MyArchitecture: public Assembler::Architecture { @@ -1054,7 +1239,9 @@ class MyOffset: public Assembler::Offset { virtual unsigned value() { assert(c, resolved()); - return block->start + (offset - block->offset); + + return block->start + (offset - block->offset) + + padding(block->firstPadding, block->start, block->offset, offset); } Context* c;