2008-06-25 20:53:48 +00:00
|
|
|
/* Copyright (c) 2008, Avian Contributors
|
|
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software
|
|
|
|
for any purpose with or without fee is hereby granted, provided
|
|
|
|
that the above copyright notice and this permission notice appear
|
|
|
|
in all copies.
|
|
|
|
|
|
|
|
There is NO WARRANTY for this software. See license.txt for
|
|
|
|
details. */
|
|
|
|
|
2008-02-08 23:18:57 +00:00
|
|
|
#include "assembler.h"
|
2008-02-09 20:11:37 +00:00
|
|
|
#include "vector.h"
|
2008-02-08 23:18:57 +00:00
|
|
|
|
|
|
|
using namespace vm;
|
|
|
|
|
2008-04-30 16:46:46 +00:00
|
|
|
#define INDEX1(a, b) ((a) + (UnaryOperationCount * (b)))
|
2008-02-12 00:20:32 +00:00
|
|
|
|
|
|
|
#define CAST1(x) reinterpret_cast<UnaryOperationType>(x)
|
|
|
|
|
|
|
|
#define INDEX2(a, b, c) \
|
|
|
|
((a) \
|
|
|
|
+ (BinaryOperationCount * (b)) \
|
|
|
|
+ (BinaryOperationCount * OperandTypeCount * (c)))
|
|
|
|
|
|
|
|
#define CAST2(x) reinterpret_cast<BinaryOperationType>(x)
|
|
|
|
|
2008-02-08 23:18:57 +00:00
|
|
|
namespace {
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
enum {
|
2008-02-08 23:18:57 +00:00
|
|
|
rax = 0,
|
|
|
|
rcx = 1,
|
|
|
|
rdx = 2,
|
|
|
|
rbx = 3,
|
|
|
|
rsp = 4,
|
|
|
|
rbp = 5,
|
|
|
|
rsi = 6,
|
|
|
|
rdi = 7,
|
|
|
|
r8 = 8,
|
|
|
|
r9 = 9,
|
|
|
|
r10 = 10,
|
|
|
|
r11 = 11,
|
|
|
|
r12 = 12,
|
|
|
|
r13 = 13,
|
|
|
|
r14 = 14,
|
|
|
|
r15 = 15,
|
|
|
|
};
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
inline bool
|
|
|
|
isInt8(intptr_t v)
|
|
|
|
{
|
|
|
|
return v == static_cast<int8_t>(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
isInt32(intptr_t v)
|
|
|
|
{
|
|
|
|
return v == static_cast<int32_t>(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
class Task;
|
|
|
|
|
|
|
|
class Context {
|
|
|
|
public:
|
|
|
|
Context(System* s, Allocator* a, Zone* zone):
|
2008-03-13 23:43:11 +00:00
|
|
|
s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0)
|
2008-02-12 00:20:32 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
Zone* zone;
|
2008-03-13 23:43:11 +00:00
|
|
|
Assembler::Client* client;
|
2008-02-12 00:20:32 +00:00
|
|
|
Vector code;
|
|
|
|
Task* tasks;
|
|
|
|
uint8_t* result;
|
|
|
|
};
|
|
|
|
|
|
|
|
inline void NO_RETURN
|
|
|
|
abort(Context* c)
|
|
|
|
{
|
|
|
|
abort(c->s);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
inline void
|
|
|
|
assert(Context* c, bool v)
|
|
|
|
{
|
|
|
|
assert(c->s, v);
|
|
|
|
}
|
|
|
|
#endif // not NDEBUG
|
|
|
|
|
|
|
|
inline void
|
|
|
|
expect(Context* c, bool v)
|
|
|
|
{
|
|
|
|
expect(c->s, v);
|
|
|
|
}
|
|
|
|
|
2008-04-28 22:08:31 +00:00
|
|
|
ResolvedPromise*
|
|
|
|
resolved(Context* c, int64_t value)
|
|
|
|
{
|
|
|
|
return new (c->zone->allocate(sizeof(ResolvedPromise)))
|
|
|
|
ResolvedPromise(value);
|
|
|
|
}
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
class CodePromise: public Promise {
|
|
|
|
public:
|
|
|
|
CodePromise(Context* c, unsigned offset): c(c), offset(offset) { }
|
|
|
|
|
|
|
|
virtual int64_t value() {
|
|
|
|
if (resolved()) {
|
|
|
|
return reinterpret_cast<intptr_t>(c->result + offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool resolved() {
|
|
|
|
return c->result != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Context* c;
|
|
|
|
unsigned offset;
|
|
|
|
};
|
|
|
|
|
|
|
|
CodePromise*
|
|
|
|
codePromise(Context* c, unsigned offset)
|
|
|
|
{
|
|
|
|
return new (c->zone->allocate(sizeof(CodePromise))) CodePromise(c, offset);
|
|
|
|
}
|
|
|
|
|
2008-02-08 23:18:57 +00:00
|
|
|
class Task {
|
|
|
|
public:
|
2008-02-09 20:11:37 +00:00
|
|
|
Task(Task* next): next(next) { }
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
virtual void run(Context* c) = 0;
|
2008-02-09 20:11:37 +00:00
|
|
|
|
|
|
|
Task* next;
|
2008-02-08 23:18:57 +00:00
|
|
|
};
|
|
|
|
|
2008-11-29 23:08:14 +00:00
|
|
|
void*
|
2008-11-27 20:59:40 +00:00
|
|
|
resolveOffset(System* s, uint8_t* instruction, unsigned instructionSize,
|
|
|
|
int64_t value)
|
|
|
|
{
|
|
|
|
intptr_t v = reinterpret_cast<uint8_t*>(value)
|
|
|
|
- instruction - instructionSize;
|
|
|
|
|
|
|
|
expect(s, isInt32(v));
|
|
|
|
|
|
|
|
int32_t v4 = v;
|
|
|
|
memcpy(instruction + instructionSize - 4, &v4, 4);
|
2008-11-29 23:08:14 +00:00
|
|
|
return instruction + instructionSize - 4;
|
2008-11-27 20:59:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class OffsetListener: public Promise::Listener {
|
|
|
|
public:
|
|
|
|
OffsetListener(System* s, uint8_t* instruction,
|
|
|
|
unsigned instructionSize):
|
|
|
|
s(s),
|
|
|
|
instruction(instruction),
|
|
|
|
instructionSize(instructionSize)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual void* resolve(int64_t value) {
|
2008-11-29 23:08:14 +00:00
|
|
|
return resolveOffset(s, instruction, instructionSize, value);
|
2008-11-27 20:59:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
uint8_t* instruction;
|
|
|
|
unsigned instructionSize;
|
|
|
|
};
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
class OffsetTask: public Task {
|
|
|
|
public:
|
2008-02-17 20:57:40 +00:00
|
|
|
OffsetTask(Task* next, Promise* promise, unsigned instructionOffset,
|
2008-02-12 00:20:32 +00:00
|
|
|
unsigned instructionSize):
|
|
|
|
Task(next),
|
|
|
|
promise(promise),
|
|
|
|
instructionOffset(instructionOffset),
|
|
|
|
instructionSize(instructionSize)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual void run(Context* c) {
|
2008-11-27 20:59:40 +00:00
|
|
|
if (promise->resolved()) {
|
|
|
|
resolveOffset
|
|
|
|
(c->s, c->result + instructionOffset, instructionSize,
|
|
|
|
promise->value());
|
|
|
|
} else {
|
|
|
|
new (promise->listen(sizeof(OffsetListener)))
|
|
|
|
OffsetListener(c->s, c->result + instructionOffset, instructionSize);
|
|
|
|
}
|
2008-02-12 00:20:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Promise* promise;
|
2008-02-17 20:57:40 +00:00
|
|
|
unsigned instructionOffset;
|
2008-02-12 00:20:32 +00:00
|
|
|
unsigned instructionSize;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
appendOffsetTask(Context* c, Promise* promise, int instructionOffset,
|
|
|
|
unsigned instructionSize)
|
|
|
|
{
|
|
|
|
c->tasks = new (c->zone->allocate(sizeof(OffsetTask))) OffsetTask
|
|
|
|
(c->tasks, promise, instructionOffset, instructionSize);
|
|
|
|
}
|
|
|
|
|
2008-11-27 20:59:40 +00:00
|
|
|
void
|
2008-11-28 04:58:32 +00:00
|
|
|
copy(System* s, void* dst, int64_t src, unsigned size)
|
2008-11-27 20:59:40 +00:00
|
|
|
{
|
2008-11-28 04:58:32 +00:00
|
|
|
switch (size) {
|
|
|
|
case 4: {
|
|
|
|
int32_t v = src;
|
|
|
|
memcpy(dst, &v, 4);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case 8: {
|
|
|
|
int64_t v = src;
|
|
|
|
memcpy(dst, &v, 8);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default: abort(s);
|
|
|
|
}
|
2008-11-27 20:59:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class ImmediateListener: public Promise::Listener {
|
|
|
|
public:
|
2008-11-28 04:58:32 +00:00
|
|
|
ImmediateListener(System* s, void* dst, unsigned size):
|
|
|
|
s(s), dst(dst), size(size)
|
|
|
|
{ }
|
2008-11-27 20:59:40 +00:00
|
|
|
|
|
|
|
virtual void* resolve(int64_t value) {
|
2008-11-28 04:58:32 +00:00
|
|
|
copy(s, dst, value, size);
|
|
|
|
return dst;
|
2008-11-27 20:59:40 +00:00
|
|
|
}
|
|
|
|
|
2008-11-28 04:58:32 +00:00
|
|
|
System* s;
|
2008-11-27 20:59:40 +00:00
|
|
|
void* dst;
|
2008-11-28 04:58:32 +00:00
|
|
|
unsigned size;
|
2008-11-27 20:59:40 +00:00
|
|
|
};
|
|
|
|
|
2008-02-17 20:57:40 +00:00
|
|
|
class ImmediateTask: public Task {
|
|
|
|
public:
|
2008-11-28 04:58:32 +00:00
|
|
|
ImmediateTask(Task* next, Promise* promise, unsigned offset, unsigned size):
|
2008-02-17 20:57:40 +00:00
|
|
|
Task(next),
|
|
|
|
promise(promise),
|
2008-11-28 04:58:32 +00:00
|
|
|
offset(offset),
|
|
|
|
size(size)
|
2008-02-17 20:57:40 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual void run(Context* c) {
|
2008-11-23 23:58:01 +00:00
|
|
|
if (promise->resolved()) {
|
2008-11-28 04:58:32 +00:00
|
|
|
copy(c->s, c->result + offset, promise->value(), size);
|
2008-11-27 20:59:40 +00:00
|
|
|
} else {
|
|
|
|
new (promise->listen(sizeof(ImmediateListener)))
|
2008-11-28 04:58:32 +00:00
|
|
|
ImmediateListener(c->s, c->result + offset, size);
|
2008-11-23 23:58:01 +00:00
|
|
|
}
|
2008-02-17 20:57:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Promise* promise;
|
|
|
|
unsigned offset;
|
2008-11-28 04:58:32 +00:00
|
|
|
unsigned size;
|
2008-02-17 20:57:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
void
|
2008-11-28 04:58:32 +00:00
|
|
|
appendImmediateTask(Context* c, Promise* promise, unsigned offset,
|
|
|
|
unsigned size)
|
2008-02-17 20:57:40 +00:00
|
|
|
{
|
|
|
|
c->tasks = new (c->zone->allocate(sizeof(ImmediateTask))) ImmediateTask
|
2008-11-28 04:58:32 +00:00
|
|
|
(c->tasks, promise, offset, size);
|
2008-02-17 20:57:40 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
void
|
|
|
|
encode(Context* c, uint8_t* instruction, unsigned length, int a, int b,
|
|
|
|
int32_t displacement, int index, unsigned scale)
|
|
|
|
{
|
|
|
|
c->code.append(instruction, length);
|
|
|
|
|
|
|
|
uint8_t width;
|
|
|
|
if (displacement == 0 and b != rbp) {
|
|
|
|
width = 0;
|
|
|
|
} else if (isInt8(displacement)) {
|
|
|
|
width = 0x40;
|
|
|
|
} else {
|
|
|
|
width = 0x80;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index == -1) {
|
|
|
|
c->code.append(width | (a << 3) | b);
|
|
|
|
if (b == rsp) {
|
|
|
|
c->code.append(0x24);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert(c, b != rsp);
|
|
|
|
c->code.append(width | (a << 3) | 4);
|
|
|
|
c->code.append((log(scale) << 6) | (index << 3) | b);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (displacement == 0 and b != rbp) {
|
|
|
|
// do nothing
|
|
|
|
} else if (isInt8(displacement)) {
|
|
|
|
c->code.append(displacement);
|
|
|
|
} else {
|
|
|
|
c->code.append4(displacement);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-04-13 19:48:20 +00:00
|
|
|
rex(Context* c, uint8_t mask, int r)
|
2008-02-12 00:20:32 +00:00
|
|
|
{
|
|
|
|
if (BytesPerWord == 8) {
|
2008-04-13 19:48:20 +00:00
|
|
|
c->code.append(mask | ((r & 8) >> 3));
|
2008-02-12 00:20:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-04-13 19:48:20 +00:00
|
|
|
rex(Context* c)
|
2008-02-12 00:20:32 +00:00
|
|
|
{
|
2008-04-13 19:48:20 +00:00
|
|
|
rex(c, 0x48, rax);
|
|
|
|
}
|
2008-02-12 00:20:32 +00:00
|
|
|
|
2008-04-13 19:48:20 +00:00
|
|
|
void
|
|
|
|
encode(Context* c, uint8_t instruction, int a, Assembler::Memory* b, bool rex)
|
|
|
|
{
|
2008-02-12 00:20:32 +00:00
|
|
|
if (rex) {
|
|
|
|
::rex(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
encode(c, &instruction, 1, a, b->base, b->offset, b->index, b->scale);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
encode2(Context* c, uint16_t instruction, int a, Assembler::Memory* b,
|
|
|
|
bool rex)
|
|
|
|
{
|
|
|
|
if (rex) {
|
|
|
|
::rex(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t i[2] = { instruction >> 8, instruction & 0xff };
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
c->code.append(0xc3);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
unconditional(Context* c, unsigned jump, Assembler::Constant* a)
|
|
|
|
{
|
|
|
|
appendOffsetTask(c, a->value, c->code.length(), 5);
|
|
|
|
|
|
|
|
c->code.append(jump);
|
|
|
|
c->code.append4(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
conditional(Context* c, unsigned condition, Assembler::Constant* a)
|
|
|
|
{
|
|
|
|
appendOffsetTask(c, a->value, c->code.length(), 6);
|
|
|
|
|
|
|
|
c->code.append(0x0f);
|
|
|
|
c->code.append(condition);
|
|
|
|
c->code.append4(0);
|
|
|
|
}
|
|
|
|
|
2008-04-17 22:07:32 +00:00
|
|
|
void
|
|
|
|
moveCR(Context*, unsigned, Assembler::Constant*, Assembler::Register*);
|
|
|
|
|
|
|
|
void
|
|
|
|
callR(Context*, unsigned, Assembler::Register*);
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
void
|
2008-06-02 14:13:20 +00:00
|
|
|
callC(Context* c, unsigned size UNUSED, Assembler::Constant* a)
|
2008-02-12 00:20:32 +00:00
|
|
|
{
|
|
|
|
assert(c, size == BytesPerWord);
|
|
|
|
|
2008-06-02 13:49:09 +00:00
|
|
|
unconditional(c, 0xe8, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
longCallC(Context* c, unsigned size, Assembler::Constant* a)
|
|
|
|
{
|
|
|
|
assert(c, size == BytesPerWord);
|
|
|
|
|
2008-04-13 19:48:20 +00:00
|
|
|
if (BytesPerWord == 8) {
|
|
|
|
Assembler::Register r(r10);
|
|
|
|
moveCR(c, size, a, &r);
|
|
|
|
callR(c, size, &r);
|
|
|
|
} else {
|
2008-06-02 13:49:09 +00:00
|
|
|
callC(c, size, a);
|
2008-04-13 19:48:20 +00:00
|
|
|
}
|
2008-02-12 00:20:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-02-17 22:29:04 +00:00
|
|
|
alignedCallC(Context* c, unsigned size, Assembler::Constant* a)
|
|
|
|
{
|
2008-06-02 13:49:09 +00:00
|
|
|
while ((c->code.length() + 1) % 4) {
|
|
|
|
c->code.append(0x90);
|
2008-02-17 22:29:04 +00:00
|
|
|
}
|
|
|
|
callC(c, size, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
callR(Context* c, unsigned size UNUSED, Assembler::Register* a)
|
2008-02-12 00:20:32 +00:00
|
|
|
{
|
|
|
|
assert(c, size == BytesPerWord);
|
|
|
|
|
2008-04-13 19:48:20 +00:00
|
|
|
if (a->low & 8) rex(c, 0x40, a->low);
|
2008-02-12 00:20:32 +00:00
|
|
|
c->code.append(0xff);
|
2008-04-20 20:43:28 +00:00
|
|
|
c->code.append(0xd0 | (a->low & 7));
|
2008-02-12 00:20:32 +00:00
|
|
|
}
|
|
|
|
|
2008-03-10 22:37:21 +00:00
|
|
|
void
|
|
|
|
callM(Context* c, unsigned size UNUSED, Assembler::Memory* a)
|
|
|
|
{
|
|
|
|
assert(c, size == BytesPerWord);
|
|
|
|
|
|
|
|
encode(c, 0xff, 2, a, false);
|
|
|
|
}
|
|
|
|
|
2008-02-17 22:29:04 +00:00
|
|
|
void
|
|
|
|
jumpR(Context* c, unsigned size UNUSED, Assembler::Register* a)
|
|
|
|
{
|
|
|
|
assert(c, size == BytesPerWord);
|
|
|
|
|
2008-05-31 22:14:27 +00:00
|
|
|
if (a->low & 8) rex(c, 0x40, a->low);
|
2008-02-17 22:29:04 +00:00
|
|
|
c->code.append(0xff);
|
2008-05-31 22:14:27 +00:00
|
|
|
c->code.append(0xe0 | (a->low & 7));
|
2008-02-17 22:29:04 +00:00
|
|
|
}
|
|
|
|
|
2008-03-13 20:50:56 +00:00
|
|
|
void
|
2008-06-02 14:13:20 +00:00
|
|
|
jumpC(Context* c, unsigned size UNUSED, Assembler::Constant* a)
|
2008-03-13 20:50:56 +00:00
|
|
|
{
|
|
|
|
assert(c, size == BytesPerWord);
|
|
|
|
|
2008-06-02 13:49:09 +00:00
|
|
|
unconditional(c, 0xe9, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
longJumpC(Context* c, unsigned size, Assembler::Constant* a)
|
|
|
|
{
|
|
|
|
assert(c, size == BytesPerWord);
|
|
|
|
|
2008-05-31 22:14:27 +00:00
|
|
|
if (BytesPerWord == 8) {
|
|
|
|
Assembler::Register r(r10);
|
|
|
|
moveCR(c, size, a, &r);
|
|
|
|
jumpR(c, size, &r);
|
|
|
|
} else {
|
2008-06-02 13:49:09 +00:00
|
|
|
jumpC(c, size, a);
|
2008-05-31 22:14:27 +00:00
|
|
|
}
|
2008-03-13 20:50:56 +00:00
|
|
|
}
|
|
|
|
|
2008-04-20 19:35:36 +00:00
|
|
|
void
|
|
|
|
jumpM(Context* c, unsigned size UNUSED, Assembler::Memory* a)
|
|
|
|
{
|
|
|
|
assert(c, size == BytesPerWord);
|
|
|
|
|
|
|
|
encode(c, 0xff, 4, a, false);
|
|
|
|
}
|
|
|
|
|
2008-03-13 23:43:11 +00:00
|
|
|
void
|
|
|
|
jumpIfEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* a)
|
|
|
|
{
|
|
|
|
assert(c, size == BytesPerWord);
|
|
|
|
|
|
|
|
conditional(c, 0x84, a);
|
|
|
|
}
|
|
|
|
|
2008-03-15 20:24:04 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-03-13 23:43:11 +00:00
|
|
|
void
|
|
|
|
pushR(Context*, unsigned, Assembler::Register*);
|
|
|
|
|
|
|
|
void
|
|
|
|
pushC(Context* c, unsigned size, Assembler::Constant* a)
|
|
|
|
{
|
|
|
|
if (BytesPerWord == 4 and size == 8) {
|
2008-04-29 22:11:17 +00:00
|
|
|
int64_t v = a->value->value();
|
|
|
|
|
2008-03-13 23:43:11 +00:00
|
|
|
ResolvedPromise low(v & 0xFFFFFFFF);
|
|
|
|
Assembler::Constant al(&low);
|
|
|
|
|
2008-04-28 22:08:31 +00:00
|
|
|
ResolvedPromise high((v >> 32) & 0xFFFFFFFF);
|
|
|
|
Assembler::Constant ah(&high);
|
|
|
|
|
2008-03-13 23:43:11 +00:00
|
|
|
pushC(c, 4, &ah);
|
|
|
|
pushC(c, 4, &al);
|
|
|
|
} else {
|
2008-04-29 22:11:17 +00:00
|
|
|
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);
|
|
|
|
}
|
2008-03-13 23:43:11 +00:00
|
|
|
} else {
|
2008-04-29 23:16:53 +00:00
|
|
|
if (BytesPerWord == 4) {
|
|
|
|
c->code.append(0x68);
|
2008-11-28 04:58:32 +00:00
|
|
|
appendImmediateTask(c, a->value, c->code.length(), BytesPerWord);
|
2008-04-29 23:16:53 +00:00
|
|
|
c->code.appendAddress(static_cast<uintptr_t>(0));
|
|
|
|
} else {
|
|
|
|
Assembler::Register tmp(c->client->acquireTemporary());
|
|
|
|
moveCR(c, size, a, &tmp);
|
|
|
|
pushR(c, size, &tmp);
|
|
|
|
c->client->releaseTemporary(tmp.low);
|
|
|
|
}
|
2008-03-13 23:43:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-15 23:54:20 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-02-12 15:21:51 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-10 22:37:21 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-17 22:29:04 +00:00
|
|
|
void
|
|
|
|
move4To8RR(Context* c, unsigned size, Assembler::Register* a,
|
|
|
|
Assembler::Register* b);
|
|
|
|
|
2008-02-12 15:21:51 +00:00
|
|
|
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 {
|
2008-02-17 22:29:04 +00:00
|
|
|
c->code.append(0x58 | a->low);
|
|
|
|
if (BytesPerWord == 8 and size == 4) {
|
|
|
|
move4To8RR(c, 0, a, a);
|
|
|
|
}
|
2008-02-12 15:21:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-09 21:27:51 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-26 20:56:03 +00:00
|
|
|
void
|
2008-04-30 15:44:17 +00:00
|
|
|
addCarryCR(Context* c, unsigned size UNUSED, Assembler::Constant* a,
|
2008-04-28 22:08:31 +00:00
|
|
|
Assembler::Register* b)
|
2008-04-26 20:56:03 +00:00
|
|
|
{
|
2008-04-28 22:08:31 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2008-04-26 20:56:03 +00:00
|
|
|
|
2008-04-28 22:08:31 +00:00
|
|
|
void
|
|
|
|
moveRR(Context* c, unsigned size, Assembler::Register* a,
|
|
|
|
Assembler::Register* b);
|
|
|
|
|
2008-04-29 00:58:02 +00:00
|
|
|
void
|
|
|
|
xorRR(Context* c, unsigned size, Assembler::Register* a,
|
|
|
|
Assembler::Register* b);
|
|
|
|
|
2008-04-28 22:08:31 +00:00
|
|
|
void
|
|
|
|
negateR(Context* c, unsigned size, Assembler::Register* a)
|
|
|
|
{
|
|
|
|
if (BytesPerWord == 4 and size == 8) {
|
2008-05-04 19:09:12 +00:00
|
|
|
assert(c, a->low == rax and a->high == rdx);
|
2008-04-28 22:08:31 +00:00
|
|
|
|
|
|
|
ResolvedPromise zeroPromise(0);
|
|
|
|
Assembler::Constant zero(&zeroPromise);
|
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
Assembler::Register ah(a->high);
|
2008-04-28 22:08:31 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
negateR(c, 4, a);
|
|
|
|
addCarryCR(c, 4, &zero, &ah);
|
|
|
|
negateR(c, 4, &ah);
|
2008-04-28 22:08:31 +00:00
|
|
|
} else {
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
2008-04-28 22:08:31 +00:00
|
|
|
c->code.append(0xf7);
|
|
|
|
c->code.append(0xd8 | a->low);
|
|
|
|
}
|
2008-04-26 20:56:03 +00:00
|
|
|
}
|
|
|
|
|
2008-02-17 20:57:40 +00:00
|
|
|
void
|
2008-02-17 22:29:04 +00:00
|
|
|
leaMR(Context* c, unsigned size, Assembler::Memory* b, Assembler::Register* a)
|
2008-02-17 20:57:40 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
void
|
2008-04-28 22:08:31 +00:00
|
|
|
moveCR(Context* c, unsigned size, Assembler::Constant* a,
|
2008-02-12 00:20:32 +00:00
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-04-28 22:08:31 +00:00
|
|
|
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);
|
2008-02-12 00:20:32 +00:00
|
|
|
|
2008-04-28 22:08:31 +00:00
|
|
|
moveCR(c, 4, &al, b);
|
|
|
|
moveCR(c, 4, &ah, &bh);
|
2008-02-17 20:57:40 +00:00
|
|
|
} else {
|
2008-04-28 22:08:31 +00:00
|
|
|
rex(c, 0x48, b->low);
|
|
|
|
c->code.append(0xb8 | b->low);
|
|
|
|
if (a->value->resolved()) {
|
|
|
|
c->code.appendAddress(a->value->value());
|
|
|
|
} else {
|
2008-11-28 04:58:32 +00:00
|
|
|
appendImmediateTask(c, a->value, c->code.length(), BytesPerWord);
|
2008-04-28 22:08:31 +00:00
|
|
|
c->code.appendAddress(static_cast<uintptr_t>(0));
|
|
|
|
}
|
2008-02-17 20:57:40 +00:00
|
|
|
}
|
2008-02-12 00:20:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-04-28 15:53:48 +00:00
|
|
|
moveCM(Context* c, unsigned size, Assembler::Constant* a,
|
2008-02-12 00:20:32 +00:00
|
|
|
Assembler::Memory* b)
|
|
|
|
{
|
2008-05-23 00:16:44 +00:00
|
|
|
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:
|
2008-05-31 22:14:27 +00:00
|
|
|
encode(c, 0xc7, 0, b, false);
|
2008-11-28 04:58:32 +00:00
|
|
|
if (a->value->resolved()) {
|
|
|
|
c->code.append4(a->value->value());
|
|
|
|
} else {
|
|
|
|
appendImmediateTask(c, a->value, c->code.length(), 4);
|
|
|
|
c->code.append4(0);
|
|
|
|
}
|
2008-05-23 00:16:44 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 8: {
|
2008-11-28 04:58:32 +00:00
|
|
|
int64_t v = a->value->value();
|
|
|
|
|
2008-04-28 15:53:48 +00:00
|
|
|
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);
|
2008-05-23 00:16:44 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
default: abort(c);
|
2008-04-28 15:53:48 +00:00
|
|
|
}
|
2008-02-12 00:20:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
moveRR(Context* c, unsigned size, Assembler::Register* a,
|
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
|
|
|
if (BytesPerWord == 4 and size == 8) {
|
2008-03-15 23:54:20 +00:00
|
|
|
Assembler::Register ah(a->high);
|
|
|
|
Assembler::Register bh(b->high);
|
2008-02-12 15:21:51 +00:00
|
|
|
|
|
|
|
moveRR(c, 4, a, b);
|
2008-02-12 00:20:32 +00:00
|
|
|
moveRR(c, 4, &ah, &bh);
|
|
|
|
} else {
|
2008-03-16 19:38:43 +00:00
|
|
|
switch (size) {
|
|
|
|
case 1:
|
2008-05-22 17:15:18 +00:00
|
|
|
if (BytesPerWord == 4 and a->low > rbx) {
|
|
|
|
assert(c, b->low <= rbx);
|
2008-04-28 22:08:31 +00:00
|
|
|
|
2008-05-22 17:15:18 +00:00
|
|
|
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);
|
|
|
|
}
|
2008-03-16 19:38:43 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
2008-04-27 20:15:18 +00:00
|
|
|
rex(c);
|
2008-04-28 16:52:54 +00:00
|
|
|
c->code.append(0x0f);
|
2008-03-16 19:38:43 +00:00
|
|
|
c->code.append(0xbf);
|
2008-04-26 20:56:03 +00:00
|
|
|
c->code.append(0xc0 | (b->low << 3) | a->low);
|
2008-03-16 19:38:43 +00:00
|
|
|
break;
|
2008-03-15 21:02:19 +00:00
|
|
|
|
2008-03-16 19:38:43 +00:00
|
|
|
case 8:
|
|
|
|
case 4:
|
2008-05-18 00:13:27 +00:00
|
|
|
if (a->low != b->low) {
|
|
|
|
rex(c);
|
|
|
|
c->code.append(0x89);
|
|
|
|
c->code.append(0xc0 | (a->low << 3) | b->low);
|
|
|
|
}
|
2008-03-16 19:38:43 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-02-12 00:20:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-15 21:02:19 +00:00
|
|
|
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 {
|
2008-05-04 19:09:12 +00:00
|
|
|
assert(c, a->low <= rbx);
|
2008-04-28 22:08:31 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
encode(c, 0x88, a->low, b, false);
|
2008-03-15 21:02:19 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
encode2(c, 0x6689, a->low, b, false);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BytesPerWord:
|
|
|
|
encode(c, 0x89, a->low, b, true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-11 14:59:05 +00:00
|
|
|
void
|
|
|
|
move4To8CR(Context* c, unsigned, Assembler::Constant* a,
|
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
|
|
|
moveCR(c, 8, a, b);
|
|
|
|
}
|
|
|
|
|
2008-04-29 00:58:02 +00:00
|
|
|
void
|
2008-05-04 19:09:12 +00:00
|
|
|
move4To8RR(Context* c, unsigned, Assembler::Register* a,
|
2008-02-17 22:29:04 +00:00
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-04-21 02:50:46 +00:00
|
|
|
if (BytesPerWord == 8) {
|
|
|
|
rex(c);
|
|
|
|
c->code.append(0x63);
|
2008-04-27 20:15:18 +00:00
|
|
|
c->code.append(0xc0 | (b->low << 3) | a->low);
|
2008-04-21 02:50:46 +00:00
|
|
|
} else {
|
|
|
|
if (a->low == rax and b->low == rax and b->high == rdx) {
|
|
|
|
c->code.append(0x99); // cdq
|
|
|
|
} else {
|
2008-05-04 19:09:12 +00:00
|
|
|
assert(c, b->low == rax and b->high == rdx);
|
2008-02-17 22:29:04 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
moveRR(c, 4, a, b);
|
|
|
|
move4To8RR(c, 0, b, b);
|
2008-04-21 02:50:46 +00:00
|
|
|
}
|
|
|
|
}
|
2008-02-17 22:29:04 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 02:06:12 +00:00
|
|
|
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);
|
2008-02-12 15:21:51 +00:00
|
|
|
|
|
|
|
moveMR(c, 4, a, b);
|
2008-02-12 02:06:12 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-17 20:57:40 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-03-13 23:43:11 +00:00
|
|
|
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)
|
|
|
|
{
|
2008-04-21 02:50:46 +00:00
|
|
|
if (BytesPerWord == 8 or size <= 4) {
|
2008-05-19 04:28:47 +00:00
|
|
|
uint32_t mask;
|
|
|
|
if (BytesPerWord == 4 and size == 1) {
|
|
|
|
mask = (1 << rax) | (1 << rcx) | (1 << rdx) | (1 << rbx);
|
|
|
|
} else {
|
|
|
|
mask = ~static_cast<uint32_t>(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Assembler::Register tmp(c->client->acquireTemporary(mask));
|
2008-04-21 02:50:46 +00:00
|
|
|
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);
|
|
|
|
}
|
2008-03-13 23:43:11 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
void
|
|
|
|
move4To8MR(Context* c, unsigned, Assembler::Memory* a, Assembler::Register* b)
|
|
|
|
{
|
2008-04-21 02:50:46 +00:00
|
|
|
if (BytesPerWord == 8) {
|
|
|
|
encode(c, 0x63, b->low, a, true);
|
|
|
|
} else {
|
2008-05-04 19:09:12 +00:00
|
|
|
assert(c, b->low == rax and b->high == rdx);
|
2008-04-28 22:08:31 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
moveMR(c, 4, a, b);
|
|
|
|
move4To8RR(c, 0, b, b);
|
2008-04-21 02:50:46 +00:00
|
|
|
}
|
2008-02-12 00:20:32 +00:00
|
|
|
}
|
|
|
|
|
2008-03-15 23:54:20 +00:00
|
|
|
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);
|
2008-04-20 02:04:15 +00:00
|
|
|
c->code.append(0xc0 | (b->low << 3) | a->low);
|
2008-03-15 23:54:20 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default: abort(c); // todo
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-14 23:33:55 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-05-13 17:28:19 +00:00
|
|
|
void
|
2008-05-14 23:19:41 +00:00
|
|
|
addCM(Context* c, unsigned size UNUSED, Assembler::Constant* a,
|
2008-05-13 17:28:19 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-02 14:52:35 +00:00
|
|
|
void
|
|
|
|
addRR(Context* c, unsigned size, Assembler::Register* a,
|
|
|
|
Assembler::Register* b);
|
|
|
|
|
2008-02-17 22:29:04 +00:00
|
|
|
void
|
2008-04-29 16:56:29 +00:00
|
|
|
addCR(Context* c, unsigned size, Assembler::Constant* a,
|
2008-03-09 21:27:51 +00:00
|
|
|
Assembler::Register* b)
|
2008-02-17 22:29:04 +00:00
|
|
|
{
|
|
|
|
int64_t v = a->value->value();
|
|
|
|
if (v) {
|
2008-04-29 16:56:29 +00:00
|
|
|
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);
|
2008-02-17 22:29:04 +00:00
|
|
|
} else {
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
2008-04-29 16:56:29 +00:00
|
|
|
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 {
|
2008-07-02 14:52:35 +00:00
|
|
|
Assembler::Register tmp(c->client->acquireTemporary());
|
|
|
|
moveCR(c, size, a, &tmp);
|
|
|
|
addRR(c, size, &tmp, b);
|
|
|
|
c->client->releaseTemporary(tmp.low);
|
2008-04-29 16:56:29 +00:00
|
|
|
}
|
2008-02-17 22:29:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-28 22:08:31 +00:00
|
|
|
void
|
2008-04-30 15:44:17 +00:00
|
|
|
subtractBorrowCR(Context* c, unsigned size UNUSED, Assembler::Constant* a,
|
2008-04-28 22:08:31 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-02 14:52:35 +00:00
|
|
|
void
|
|
|
|
subtractRR(Context* c, unsigned size, Assembler::Register* a,
|
|
|
|
Assembler::Register* b);
|
|
|
|
|
2008-03-13 20:50:56 +00:00
|
|
|
void
|
2008-04-30 15:44:17 +00:00
|
|
|
subtractCR(Context* c, unsigned size, Assembler::Constant* a,
|
2008-03-13 23:43:11 +00:00
|
|
|
Assembler::Register* b)
|
2008-03-13 20:50:56 +00:00
|
|
|
{
|
|
|
|
int64_t v = a->value->value();
|
|
|
|
if (v) {
|
2008-04-28 22:08:31 +00:00
|
|
|
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);
|
2008-03-13 20:50:56 +00:00
|
|
|
} else {
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
2008-04-28 22:08:31 +00:00
|
|
|
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 {
|
2008-07-02 14:52:35 +00:00
|
|
|
Assembler::Register tmp(c->client->acquireTemporary());
|
|
|
|
moveCR(c, size, a, &tmp);
|
|
|
|
subtractRR(c, size, &tmp, b);
|
|
|
|
c->client->releaseTemporary(tmp.low);
|
2008-04-28 22:08:31 +00:00
|
|
|
}
|
2008-03-13 20:50:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-18 15:43:31 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-03-15 23:54:20 +00:00
|
|
|
void
|
2008-05-04 19:09:12 +00:00
|
|
|
subtractRR(Context* c, unsigned size, Assembler::Register* a,
|
2008-03-15 23:54:20 +00:00
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-05-18 15:43:31 +00:00
|
|
|
if (BytesPerWord == 4 and size == 8) {
|
|
|
|
Assembler::Register ah(a->high);
|
|
|
|
Assembler::Register bh(b->high);
|
2008-03-15 23:54:20 +00:00
|
|
|
|
2008-05-18 15:43:31 +00:00
|
|
|
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);
|
|
|
|
}
|
2008-03-15 23:54:20 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
void
|
2008-05-04 19:09:12 +00:00
|
|
|
addCarryRR(Context* c, unsigned size, Assembler::Register* a,
|
2008-04-28 22:08:31 +00:00
|
|
|
Assembler::Register* b)
|
2008-02-12 00:20:32 +00:00
|
|
|
{
|
2008-04-28 22:08:31 +00:00
|
|
|
assert(c, BytesPerWord == 8 or size == 4);
|
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
2008-04-28 22:08:31 +00:00
|
|
|
c->code.append(0x11);
|
2008-02-12 00:20:32 +00:00
|
|
|
c->code.append(0xc0 | (a->low << 3) | b->low);
|
|
|
|
}
|
|
|
|
|
2008-04-28 22:08:31 +00:00
|
|
|
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 {
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
2008-04-28 22:08:31 +00:00
|
|
|
c->code.append(0x01);
|
|
|
|
c->code.append(0xc0 | (a->low << 3) | b->low);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-17 20:57:40 +00:00
|
|
|
void
|
2008-03-09 21:27:51 +00:00
|
|
|
addRM(Context* c, unsigned size UNUSED, Assembler::Register* a,
|
2008-02-17 20:57:40 +00:00
|
|
|
Assembler::Memory* b)
|
|
|
|
{
|
|
|
|
assert(c, BytesPerWord == 8 or size == 4);
|
|
|
|
|
|
|
|
encode(c, 0x01, a->low, b, true);
|
|
|
|
}
|
|
|
|
|
2008-04-27 20:42:57 +00:00
|
|
|
void
|
2008-04-29 22:11:17 +00:00
|
|
|
multiplyRR(Context* c, unsigned size, Assembler::Register* a,
|
2008-04-27 20:42:57 +00:00
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-04-29 22:11:17 +00:00
|
|
|
if (BytesPerWord == 4 and size == 8) {
|
2008-05-04 19:09:12 +00:00
|
|
|
assert(c, b->high == rdx);
|
|
|
|
assert(c, b->low != rax);
|
|
|
|
assert(c, a->low != rax);
|
|
|
|
assert(c, a->high != rax);
|
|
|
|
|
|
|
|
c->client->save(rax);
|
2008-04-27 20:42:57 +00:00
|
|
|
|
2008-04-29 22:11:17 +00:00
|
|
|
Assembler::Register axdx(rax, rdx);
|
2008-05-04 19:09:12 +00:00
|
|
|
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);
|
2008-05-18 03:32:14 +00:00
|
|
|
c->code.append(0xe0 | a->low);
|
2008-05-04 19:09:12 +00:00
|
|
|
|
|
|
|
addRR(c, 4, b, &bh);
|
2008-04-29 22:11:17 +00:00
|
|
|
moveRR(c, 4, &axdx, b);
|
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
c->client->restore(rax);
|
2008-04-29 22:11:17 +00:00
|
|
|
} else {
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
2008-04-29 22:11:17 +00:00
|
|
|
c->code.append(0x0f);
|
|
|
|
c->code.append(0xaf);
|
|
|
|
c->code.append(0xc0 | (b->low << 3) | a->low);
|
|
|
|
}
|
2008-04-27 20:42:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
multiplyCR(Context* c, unsigned size, Assembler::Constant* a,
|
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-04-29 22:11:17 +00:00
|
|
|
if (BytesPerWord == 4 and size == 8) {
|
2008-05-04 19:09:12 +00:00
|
|
|
const uint32_t mask = ~((1 << rax) | (1 << rdx));
|
|
|
|
Assembler::Register tmp(c->client->acquireTemporary(mask),
|
|
|
|
c->client->acquireTemporary(mask));
|
2008-04-27 20:42:57 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
moveCR(c, size, a, &tmp);
|
2008-05-06 21:13:02 +00:00
|
|
|
multiplyRR(c, size, &tmp, b);
|
2008-04-29 22:11:17 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
c->client->releaseTemporary(tmp.low);
|
|
|
|
c->client->releaseTemporary(tmp.high);
|
2008-04-29 22:11:17 +00:00
|
|
|
} else {
|
|
|
|
int64_t v = a->value->value();
|
2008-06-11 00:14:15 +00:00
|
|
|
if (v != 1) {
|
2008-04-29 22:11:17 +00:00
|
|
|
if (isInt32(v)) {
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
2008-04-29 22:11:17 +00:00
|
|
|
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);
|
|
|
|
}
|
2008-04-27 20:42:57 +00:00
|
|
|
} else {
|
2008-04-29 22:11:17 +00:00
|
|
|
Assembler::Register tmp(c->client->acquireTemporary());
|
|
|
|
moveCR(c, size, a, &tmp);
|
|
|
|
multiplyRR(c, size, &tmp, b);
|
|
|
|
c->client->releaseTemporary(tmp.low);
|
2008-04-27 20:42:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-26 20:56:03 +00:00
|
|
|
void
|
|
|
|
divideRR(Context* c, unsigned size, Assembler::Register* a,
|
2008-05-14 23:19:41 +00:00
|
|
|
Assembler::Register* b UNUSED)
|
2008-04-26 20:56:03 +00:00
|
|
|
{
|
2008-05-04 19:09:12 +00:00
|
|
|
assert(c, BytesPerWord == 8 or size == 4);
|
2008-04-26 20:56:03 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
assert(c, b->low == rax);
|
|
|
|
assert(c, a->low != rdx);
|
2008-04-29 00:58:02 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
c->client->save(rdx);
|
2008-04-26 20:56:03 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
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);
|
2008-04-26 20:56:03 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
c->client->restore(rdx);
|
2008-04-27 20:15:18 +00:00
|
|
|
}
|
|
|
|
|
2008-04-27 20:42:57 +00:00
|
|
|
void
|
|
|
|
divideCR(Context* c, unsigned size, Assembler::Constant* a,
|
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-05-04 19:09:12 +00:00
|
|
|
assert(c, BytesPerWord == 8 or size == 4);
|
2008-04-27 20:42:57 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
const uint32_t mask = ~((1 << rax) | (1 << rdx));
|
|
|
|
Assembler::Register tmp(c->client->acquireTemporary(mask));
|
2008-04-27 20:42:57 +00:00
|
|
|
moveCR(c, size, a, &tmp);
|
|
|
|
divideRR(c, size, &tmp, b);
|
|
|
|
c->client->releaseTemporary(tmp.low);
|
|
|
|
}
|
|
|
|
|
2008-04-27 20:15:18 +00:00
|
|
|
void
|
|
|
|
remainderRR(Context* c, unsigned size, Assembler::Register* a,
|
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-05-04 19:09:12 +00:00
|
|
|
assert(c, BytesPerWord == 8 or size == 4);
|
2008-04-29 00:58:02 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
assert(c, b->low == rax);
|
|
|
|
assert(c, a->low != rdx);
|
2008-04-27 20:15:18 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
c->client->save(rdx);
|
2008-04-27 20:15:18 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
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);
|
2008-04-27 20:15:18 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
Assembler::Register dx(rdx);
|
|
|
|
moveRR(c, BytesPerWord, &dx, b);
|
2008-04-28 22:08:31 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
c->client->restore(rdx);
|
2008-04-26 20:56:03 +00:00
|
|
|
}
|
|
|
|
|
2008-04-30 15:44:17 +00:00
|
|
|
void
|
|
|
|
remainderCR(Context* c, unsigned size, Assembler::Constant* a,
|
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-05-04 19:09:12 +00:00
|
|
|
assert(c, BytesPerWord == 8 or size == 4);
|
2008-04-30 15:44:17 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
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);
|
2008-04-30 15:44:17 +00:00
|
|
|
}
|
|
|
|
|
2008-04-27 20:42:57 +00:00
|
|
|
void
|
2008-04-29 20:24:52 +00:00
|
|
|
andRR(Context* c, unsigned size, Assembler::Register* a,
|
2008-04-27 20:42:57 +00:00
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-04-29 20:24:52 +00:00
|
|
|
if (BytesPerWord == 4 and size == 8) {
|
|
|
|
Assembler::Register ah(a->high);
|
|
|
|
Assembler::Register bh(b->high);
|
2008-04-27 20:42:57 +00:00
|
|
|
|
2008-04-29 20:24:52 +00:00
|
|
|
andRR(c, 4, a, b);
|
|
|
|
andRR(c, 4, &ah, &bh);
|
|
|
|
} else {
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
2008-04-29 20:24:52 +00:00
|
|
|
c->code.append(0x21);
|
|
|
|
c->code.append(0xc0 | (a->low << 3) | b->low);
|
|
|
|
}
|
2008-04-27 20:42:57 +00:00
|
|
|
}
|
|
|
|
|
2008-03-10 22:37:21 +00:00
|
|
|
void
|
2008-04-29 16:56:29 +00:00
|
|
|
andCR(Context* c, unsigned size, Assembler::Constant* a,
|
2008-03-10 22:37:21 +00:00
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-03-13 23:43:11 +00:00
|
|
|
int64_t v = a->value->value();
|
|
|
|
|
2008-04-29 16:56:29 +00:00
|
|
|
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)) {
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
2008-04-29 16:56:29 +00:00
|
|
|
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);
|
|
|
|
}
|
2008-04-27 20:42:57 +00:00
|
|
|
} else {
|
2008-04-29 16:56:29 +00:00
|
|
|
Assembler::Register tmp(c->client->acquireTemporary());
|
|
|
|
moveCR(c, size, a, &tmp);
|
|
|
|
andRR(c, size, &tmp, b);
|
|
|
|
c->client->releaseTemporary(tmp.low);
|
2008-04-27 20:42:57 +00:00
|
|
|
}
|
2008-03-10 22:37:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
andCM(Context* c, unsigned size UNUSED, Assembler::Constant* a,
|
|
|
|
Assembler::Memory* b)
|
|
|
|
{
|
|
|
|
assert(c, BytesPerWord == 8 or size == 4);
|
|
|
|
|
2008-03-13 23:43:11 +00:00
|
|
|
int64_t v = a->value->value();
|
|
|
|
|
2008-03-13 20:50:56 +00:00
|
|
|
encode(c, isInt8(a->value->value()) ? 0x83 : 0x81, 5, b, true);
|
2008-03-13 23:43:11 +00:00
|
|
|
if (isInt8(v)) {
|
|
|
|
c->code.append(v);
|
|
|
|
} else if (isInt32(v)) {
|
|
|
|
c->code.append4(v);
|
|
|
|
} else {
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-28 15:53:48 +00:00
|
|
|
void
|
2008-04-29 20:24:52 +00:00
|
|
|
orRR(Context* c, unsigned size, Assembler::Register* a,
|
2008-05-04 19:09:12 +00:00
|
|
|
Assembler::Register* b)
|
2008-04-28 15:53:48 +00:00
|
|
|
{
|
2008-04-29 20:24:52 +00:00
|
|
|
if (BytesPerWord == 4 and size == 8) {
|
|
|
|
Assembler::Register ah(a->high);
|
|
|
|
Assembler::Register bh(b->high);
|
2008-04-28 15:53:48 +00:00
|
|
|
|
2008-04-29 20:24:52 +00:00
|
|
|
orRR(c, 4, a, b);
|
|
|
|
orRR(c, 4, &ah, &bh);
|
|
|
|
} else {
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
2008-04-29 20:24:52 +00:00
|
|
|
c->code.append(0x09);
|
|
|
|
c->code.append(0xc0 | (a->low << 3) | b->low);
|
|
|
|
}
|
2008-04-28 15:53:48 +00:00
|
|
|
}
|
|
|
|
|
2008-04-29 23:16:53 +00:00
|
|
|
void
|
|
|
|
orCR(Context* c, unsigned size, Assembler::Constant* a,
|
2008-05-04 19:09:12 +00:00
|
|
|
Assembler::Register* b)
|
2008-04-29 23:16:53 +00:00
|
|
|
{
|
|
|
|
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)) {
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
2008-04-29 23:16:53 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-20 22:19:11 +00:00
|
|
|
void
|
2008-04-29 16:56:29 +00:00
|
|
|
xorRR(Context* c, unsigned size, Assembler::Register* a,
|
2008-04-20 22:19:11 +00:00
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-04-29 16:56:29 +00:00
|
|
|
if (BytesPerWord == 4 and size == 8) {
|
|
|
|
Assembler::Register ah(a->high);
|
|
|
|
Assembler::Register bh(b->high);
|
2008-04-20 22:19:11 +00:00
|
|
|
|
2008-04-29 16:56:29 +00:00
|
|
|
xorRR(c, 4, a, b);
|
|
|
|
xorRR(c, 4, &ah, &bh);
|
|
|
|
} else {
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
2008-04-29 16:56:29 +00:00
|
|
|
c->code.append(0x31);
|
|
|
|
c->code.append(0xc0 | (a->low << 3) | b->low);
|
|
|
|
}
|
2008-04-20 22:19:11 +00:00
|
|
|
}
|
|
|
|
|
2008-04-27 20:42:57 +00:00
|
|
|
void
|
2008-04-29 16:56:29 +00:00
|
|
|
xorCR(Context* c, unsigned size, Assembler::Constant* a,
|
2008-04-27 20:42:57 +00:00
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
|
|
|
int64_t v = a->value->value();
|
|
|
|
if (v) {
|
2008-04-29 16:56:29 +00:00
|
|
|
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)) {
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
2008-04-29 16:56:29 +00:00
|
|
|
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);
|
|
|
|
}
|
2008-04-27 20:42:57 +00:00
|
|
|
} else {
|
2008-04-29 16:56:29 +00:00
|
|
|
Assembler::Register tmp(c->client->acquireTemporary());
|
|
|
|
moveCR(c, size, a, &tmp);
|
|
|
|
xorRR(c, size, &tmp, b);
|
|
|
|
c->client->releaseTemporary(tmp.low);
|
2008-04-27 20:42:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-28 15:53:48 +00:00
|
|
|
void
|
2008-04-29 20:24:52 +00:00
|
|
|
doShift(Context* c, void (*shift)
|
|
|
|
(Context*, unsigned, Assembler::Register*, Assembler::Register*),
|
|
|
|
int type, unsigned size, Assembler::Constant* a,
|
|
|
|
Assembler::Register* b)
|
2008-04-28 15:53:48 +00:00
|
|
|
{
|
2008-04-20 00:43:12 +00:00
|
|
|
int64_t v = a->value->value();
|
|
|
|
|
2008-04-29 20:24:52 +00:00
|
|
|
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);
|
2008-04-20 00:43:12 +00:00
|
|
|
} else {
|
2008-04-30 18:44:27 +00:00
|
|
|
if (size == 8) rex(c);
|
2008-04-29 20:24:52 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2008-04-20 00:43:12 +00:00
|
|
|
}
|
|
|
|
|
2008-03-13 23:43:11 +00:00
|
|
|
void
|
2008-04-29 20:24:52 +00:00
|
|
|
compareCR(Context* c, unsigned size, Assembler::Constant* a,
|
|
|
|
Assembler::Register* b);
|
|
|
|
|
|
|
|
void
|
|
|
|
shiftLeftRR(Context* c, unsigned size, Assembler::Register* a,
|
2008-05-04 19:09:12 +00:00
|
|
|
Assembler::Register* b)
|
2008-03-13 23:43:11 +00:00
|
|
|
{
|
2008-05-04 19:09:12 +00:00
|
|
|
assert(c, a->low == rcx);
|
2008-04-29 20:24:52 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
if (BytesPerWord == 4 and size == 8) {
|
|
|
|
// shld
|
|
|
|
c->code.append(0x0f);
|
|
|
|
c->code.append(0xa5);
|
|
|
|
c->code.append(0xc0 | (b->low << 3) | b->high);
|
2008-04-29 20:24:52 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
// shl
|
|
|
|
c->code.append(0xd3);
|
|
|
|
c->code.append(0xe0 | b->low);
|
2008-04-29 20:24:52 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
ResolvedPromise promise(32);
|
|
|
|
Assembler::Constant constant(&promise);
|
|
|
|
compareCR(c, 4, &constant, a);
|
2008-03-13 23:43:11 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
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
|
2008-04-29 20:24:52 +00:00
|
|
|
} else {
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
|
|
|
c->code.append(0xd3);
|
|
|
|
c->code.append(0xe0 | b->low);
|
2008-04-29 20:24:52 +00:00
|
|
|
}
|
2008-04-28 15:53:48 +00:00
|
|
|
}
|
2008-03-13 23:43:11 +00:00
|
|
|
|
2008-04-28 15:53:48 +00:00
|
|
|
void
|
2008-04-29 20:24:52 +00:00
|
|
|
shiftLeftCR(Context* c, unsigned size, Assembler::Constant* a,
|
2008-04-28 15:53:48 +00:00
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-04-29 20:24:52 +00:00
|
|
|
doShift(c, shiftLeftRR, 0xe0, size, a, b);
|
2008-04-28 15:53:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-04-29 20:24:52 +00:00
|
|
|
shiftRightRR(Context* c, unsigned size, Assembler::Register* a,
|
2008-04-28 15:53:48 +00:00
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-05-04 19:09:12 +00:00
|
|
|
assert(c, a->low == rcx);
|
2008-04-29 20:24:52 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
if (BytesPerWord == 4 and size == 8) {
|
|
|
|
// shrd
|
|
|
|
c->code.append(0x0f);
|
|
|
|
c->code.append(0xad);
|
|
|
|
c->code.append(0xc0 | (b->high << 3) | b->low);
|
2008-04-29 20:24:52 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
// sar
|
|
|
|
c->code.append(0xd3);
|
|
|
|
c->code.append(0xf8 | b->high);
|
2008-04-29 20:24:52 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
ResolvedPromise promise(32);
|
|
|
|
Assembler::Constant constant(&promise);
|
|
|
|
compareCR(c, 4, &constant, a);
|
2008-04-29 20:24:52 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
c->code.append(0x0f);
|
|
|
|
c->code.append(0x8c); // jl
|
|
|
|
c->code.append4(2 + 3);
|
2008-04-28 15:53:48 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
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);
|
2008-04-29 20:24:52 +00:00
|
|
|
} else {
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
|
|
|
c->code.append(0xd3);
|
|
|
|
c->code.append(0xf8 | b->low);
|
2008-04-29 20:24:52 +00:00
|
|
|
}
|
2008-04-28 15:53:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-04-29 20:24:52 +00:00
|
|
|
shiftRightCR(Context* c, unsigned size, Assembler::Constant* a,
|
2008-04-28 15:53:48 +00:00
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-04-29 20:24:52 +00:00
|
|
|
doShift(c, shiftRightRR, 0xf8, size, a, b);
|
2008-04-28 15:53:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-04-29 20:24:52 +00:00
|
|
|
unsignedShiftRightRR(Context* c, unsigned size, Assembler::Register* a,
|
2008-04-28 15:53:48 +00:00
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-05-04 19:09:12 +00:00
|
|
|
assert(c, a->low == rcx);
|
2008-04-28 15:53:48 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
if (BytesPerWord == 4 and size == 8) {
|
2008-05-18 03:32:14 +00:00
|
|
|
// shrd
|
2008-05-04 19:09:12 +00:00
|
|
|
c->code.append(0x0f);
|
2008-05-18 03:32:14 +00:00
|
|
|
c->code.append(0xad);
|
2008-05-04 19:09:12 +00:00
|
|
|
c->code.append(0xc0 | (b->high << 3) | b->low);
|
2008-04-29 20:24:52 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
// shr
|
|
|
|
c->code.append(0xd3);
|
|
|
|
c->code.append(0xe8 | b->high);
|
2008-04-29 20:24:52 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
ResolvedPromise promise(32);
|
|
|
|
Assembler::Constant constant(&promise);
|
|
|
|
compareCR(c, 4, &constant, a);
|
2008-04-29 20:24:52 +00:00
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
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
|
2008-04-29 20:24:52 +00:00
|
|
|
} else {
|
2008-05-04 19:09:12 +00:00
|
|
|
if (size == 8) rex(c);
|
|
|
|
c->code.append(0xd3);
|
|
|
|
c->code.append(0xe8 | b->low);
|
2008-04-29 20:24:52 +00:00
|
|
|
}
|
2008-04-28 15:53:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-04-29 20:24:52 +00:00
|
|
|
unsignedShiftRightCR(Context* c, unsigned size, Assembler::Constant* a,
|
2008-04-28 15:53:48 +00:00
|
|
|
Assembler::Register* b)
|
|
|
|
{
|
2008-04-29 20:24:52 +00:00
|
|
|
doShift(c, unsignedShiftRightRR, 0xe8, size, a, b);
|
2008-03-13 20:50:56 +00:00
|
|
|
}
|
|
|
|
|
2008-05-22 17:15:18 +00:00
|
|
|
void
|
2008-06-12 17:23:20 +00:00
|
|
|
compareRR(Context* c, unsigned size, Assembler::Register* a,
|
|
|
|
Assembler::Register* b)
|
2008-05-22 17:15:18 +00:00
|
|
|
{
|
2008-06-12 17:23:20 +00:00
|
|
|
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();
|
2008-05-22 17:15:18 +00:00
|
|
|
|
2008-06-12 17:23:20 +00:00
|
|
|
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);
|
|
|
|
|
2008-06-12 16:56:48 +00:00
|
|
|
int64_t v = a->value->value();
|
2008-06-12 17:23:20 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-07-31 13:53:43 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-06-12 17:23:20 +00:00
|
|
|
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);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
2008-06-12 17:23:20 +00:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah,
|
|
|
|
Assembler::Operand* bl, Assembler::Operand* bh,
|
|
|
|
BinaryOperationType compare, BinaryOperationType move)
|
|
|
|
{
|
2008-06-12 16:56:48 +00:00
|
|
|
ResolvedPromise negativePromise(-1);
|
|
|
|
Assembler::Constant negative(&negativePromise);
|
2008-05-22 17:15:18 +00:00
|
|
|
|
2008-06-12 16:56:48 +00:00
|
|
|
ResolvedPromise zeroPromise(0);
|
|
|
|
Assembler::Constant zero(&zeroPromise);
|
|
|
|
|
|
|
|
ResolvedPromise positivePromise(1);
|
|
|
|
Assembler::Constant positive(&positivePromise);
|
|
|
|
|
|
|
|
if (BytesPerWord == 8) {
|
2008-06-12 17:23:20 +00:00
|
|
|
compare(c, 8, al, bl);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2008-06-12 17:23:20 +00:00
|
|
|
move(c, 4, &zero, bl);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2008-06-12 17:23:20 +00:00
|
|
|
move(c, 4, &negative, bl);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2008-06-12 17:23:20 +00:00
|
|
|
move(c, 4, &positive, bl);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
|
|
|
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 {
|
2008-06-12 17:23:20 +00:00
|
|
|
compare(c, 4, ah, bh);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2008-06-12 17:23:20 +00:00
|
|
|
compare(c, 4, al, bl);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2008-06-12 17:23:20 +00:00
|
|
|
move(c, 4, &zero, bl);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
|
|
|
c->code.append(0xe9); // jmp
|
|
|
|
unsigned nextFirst = c->code.length();
|
|
|
|
c->code.append4(0);
|
2008-05-22 17:15:18 +00:00
|
|
|
|
2008-06-12 16:56:48 +00:00
|
|
|
int32_t lessOffset = c->code.length() - less - 4;
|
|
|
|
c->code.set(less, &lessOffset, 4);
|
2008-05-22 17:15:18 +00:00
|
|
|
|
2008-06-12 16:56:48 +00:00
|
|
|
int32_t aboveOffset = c->code.length() - above - 4;
|
|
|
|
c->code.set(above, &aboveOffset, 4);
|
|
|
|
|
2008-06-12 17:23:20 +00:00
|
|
|
move(c, 4, &negative, bl);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2008-06-12 17:23:20 +00:00
|
|
|
move(c, 4, &positive, bl);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2008-05-22 17:15:18 +00:00
|
|
|
}
|
|
|
|
|
2008-03-15 23:54:20 +00:00
|
|
|
void
|
2008-06-12 17:23:20 +00:00
|
|
|
longCompareCR(Context* c, unsigned size UNUSED, Assembler::Constant* a,
|
|
|
|
Assembler::Register* b)
|
2008-04-28 15:53:48 +00:00
|
|
|
{
|
2008-06-12 17:23:20 +00:00
|
|
|
assert(c, size == 8);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
2008-04-28 15:53:48 +00:00
|
|
|
int64_t v = a->value->value();
|
|
|
|
|
2008-06-17 15:32:46 +00:00
|
|
|
ResolvedPromise low(v & ~static_cast<uintptr_t>(0));
|
2008-06-12 17:23:20 +00:00
|
|
|
Assembler::Constant al(&low);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
2008-06-17 15:32:46 +00:00
|
|
|
ResolvedPromise high((v >> 32) & ~static_cast<uintptr_t>(0));
|
2008-06-12 17:23:20 +00:00
|
|
|
Assembler::Constant ah(&high);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
2008-06-12 17:23:20 +00:00
|
|
|
Assembler::Register bh(b->high);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
2008-06-12 17:23:20 +00:00
|
|
|
longCompare(c, &al, &ah, b, &bh, CAST2(compareCR), CAST2(moveCR));
|
2008-04-19 00:19:45 +00:00
|
|
|
}
|
|
|
|
|
2008-03-15 23:54:20 +00:00
|
|
|
void
|
2008-06-12 17:23:20 +00:00
|
|
|
longCompareRR(Context* c, unsigned size UNUSED, Assembler::Register* a,
|
|
|
|
Assembler::Register* b)
|
2008-03-15 23:54:20 +00:00
|
|
|
{
|
2008-06-12 17:23:20 +00:00
|
|
|
assert(c, size == 8);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
2008-06-12 17:23:20 +00:00
|
|
|
Assembler::Register ah(a->high);
|
|
|
|
Assembler::Register bh(b->high);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
2008-06-12 17:23:20 +00:00
|
|
|
longCompare(c, a, &ah, b, &bh, CAST2(compareRR), CAST2(moveCR));
|
2008-04-29 23:16:53 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
void
|
|
|
|
populateTables()
|
|
|
|
{
|
|
|
|
Operations[Return] = return_;
|
|
|
|
|
2008-04-17 22:07:32 +00:00
|
|
|
const int Constant = ConstantOperand;
|
|
|
|
const int Address = AddressOperand;
|
|
|
|
const int Register = RegisterOperand;
|
|
|
|
const int Memory = MemoryOperand;
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
UnaryOperations[INDEX1(Call, Constant)] = CAST1(callC);
|
2008-02-17 22:29:04 +00:00
|
|
|
UnaryOperations[INDEX1(Call, Register)] = CAST1(callR);
|
2008-03-10 22:37:21 +00:00
|
|
|
UnaryOperations[INDEX1(Call, Memory)] = CAST1(callM);
|
2008-03-13 20:50:56 +00:00
|
|
|
|
2008-06-02 13:49:09 +00:00
|
|
|
UnaryOperations[INDEX1(LongCall, Constant)] = CAST1(longCallC);
|
|
|
|
|
2008-03-13 20:50:56 +00:00
|
|
|
UnaryOperations[INDEX1(AlignedCall, Constant)] = CAST1(alignedCallC);
|
|
|
|
|
2008-03-15 20:24:04 +00:00
|
|
|
UnaryOperations[INDEX1(Jump, Constant)] = CAST1(jumpC);
|
2008-06-02 13:49:09 +00:00
|
|
|
UnaryOperations[INDEX1(Jump, Register)] = CAST1(jumpR);
|
2008-04-20 19:35:36 +00:00
|
|
|
UnaryOperations[INDEX1(Jump, Memory)] = CAST1(jumpM);
|
2008-03-13 20:50:56 +00:00
|
|
|
|
2008-06-02 13:49:09 +00:00
|
|
|
UnaryOperations[INDEX1(LongJump, Constant)] = CAST1(longJumpC);
|
|
|
|
|
2008-03-15 20:24:04 +00:00
|
|
|
UnaryOperations[INDEX1(JumpIfEqual, Constant)] = CAST1(jumpIfEqualC);
|
|
|
|
UnaryOperations[INDEX1(JumpIfNotEqual, Constant)] = CAST1(jumpIfNotEqualC);
|
|
|
|
UnaryOperations[INDEX1(JumpIfGreater, Constant)] = CAST1(jumpIfGreaterC);
|
2008-03-13 20:50:56 +00:00
|
|
|
UnaryOperations[INDEX1(JumpIfGreaterOrEqual, Constant)]
|
|
|
|
= CAST1(jumpIfGreaterOrEqualC);
|
2008-03-15 20:24:04 +00:00
|
|
|
UnaryOperations[INDEX1(JumpIfLess, Constant)] = CAST1(jumpIfLessC);
|
|
|
|
UnaryOperations[INDEX1(JumpIfLessOrEqual, Constant)]
|
|
|
|
= CAST1(jumpIfLessOrEqualC);
|
2008-03-13 20:50:56 +00:00
|
|
|
|
2008-03-13 23:43:11 +00:00
|
|
|
UnaryOperations[INDEX1(Push, Constant)] = CAST1(pushC);
|
2008-03-15 23:54:20 +00:00
|
|
|
UnaryOperations[INDEX1(Push, Address)] = CAST1(pushA);
|
2008-02-12 15:21:51 +00:00
|
|
|
UnaryOperations[INDEX1(Push, Register)] = CAST1(pushR);
|
2008-03-10 22:37:21 +00:00
|
|
|
UnaryOperations[INDEX1(Push, Memory)] = CAST1(pushM);
|
2008-03-13 20:50:56 +00:00
|
|
|
|
2008-02-12 15:21:51 +00:00
|
|
|
UnaryOperations[INDEX1(Pop, Register)] = CAST1(popR);
|
2008-03-09 21:27:51 +00:00
|
|
|
UnaryOperations[INDEX1(Pop, Memory)] = CAST1(popM);
|
2008-02-12 00:20:32 +00:00
|
|
|
|
2008-04-26 20:56:03 +00:00
|
|
|
UnaryOperations[INDEX1(Negate, Register)] = CAST1(negateR);
|
|
|
|
|
2008-02-17 22:29:04 +00:00
|
|
|
BinaryOperations[INDEX2(LoadAddress, Memory, Register)] = CAST2(leaMR);
|
2008-03-13 20:50:56 +00:00
|
|
|
|
2008-02-12 02:06:12 +00:00
|
|
|
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);
|
2008-02-17 20:57:40 +00:00
|
|
|
BinaryOperations[INDEX2(Move, Address, Register)] = CAST2(moveAR);
|
2008-03-13 23:43:11 +00:00
|
|
|
BinaryOperations[INDEX2(Move, Address, Memory)] = CAST2(moveAM);
|
|
|
|
BinaryOperations[INDEX2(Move, Memory, Memory)] = CAST2(moveMM);
|
2008-03-13 20:50:56 +00:00
|
|
|
|
2008-06-11 14:59:05 +00:00
|
|
|
BinaryOperations[INDEX2(Move4To8, Constant, Register)] = CAST2(move4To8CR);
|
2008-03-13 20:50:56 +00:00
|
|
|
BinaryOperations[INDEX2(Move4To8, Register, Register)] = CAST2(move4To8RR);
|
2008-02-12 00:20:32 +00:00
|
|
|
BinaryOperations[INDEX2(Move4To8, Memory, Register)] = CAST2(move4To8MR);
|
2008-03-13 20:50:56 +00:00
|
|
|
|
2008-03-15 23:54:20 +00:00
|
|
|
BinaryOperations[INDEX2(MoveZ, Memory, Register)] = CAST2(moveZMR);
|
|
|
|
BinaryOperations[INDEX2(MoveZ, Register, Register)] = CAST2(moveZRR);
|
|
|
|
|
2008-05-14 23:33:55 +00:00
|
|
|
BinaryOperations[INDEX2(Swap, Register, Register)] = CAST2(swapRR);
|
|
|
|
|
2008-02-17 22:29:04 +00:00
|
|
|
BinaryOperations[INDEX2(Add, Constant, Register)] = CAST2(addCR);
|
2008-02-12 00:20:32 +00:00
|
|
|
BinaryOperations[INDEX2(Add, Register, Register)] = CAST2(addRR);
|
2008-02-17 20:57:40 +00:00
|
|
|
BinaryOperations[INDEX2(Add, Register, Memory)] = CAST2(addRM);
|
2008-05-13 17:28:19 +00:00
|
|
|
BinaryOperations[INDEX2(Add, Constant, Memory)] = CAST2(addCM);
|
2008-03-13 20:50:56 +00:00
|
|
|
|
2008-04-27 20:42:57 +00:00
|
|
|
BinaryOperations[INDEX2(Multiply, Register, Register)] = CAST2(multiplyRR);
|
|
|
|
BinaryOperations[INDEX2(Multiply, Constant, Register)] = CAST2(multiplyCR);
|
|
|
|
|
2008-04-26 20:56:03 +00:00
|
|
|
BinaryOperations[INDEX2(Divide, Register, Register)] = CAST2(divideRR);
|
2008-04-27 20:42:57 +00:00
|
|
|
BinaryOperations[INDEX2(Divide, Constant, Register)] = CAST2(divideCR);
|
2008-04-26 20:56:03 +00:00
|
|
|
|
2008-04-30 15:44:17 +00:00
|
|
|
BinaryOperations[INDEX2(Remainder, Constant, Register)] = CAST2(remainderCR);
|
2008-04-27 20:15:18 +00:00
|
|
|
BinaryOperations[INDEX2(Remainder, Register, Register)] = CAST2(remainderRR);
|
|
|
|
|
2008-04-27 20:42:57 +00:00
|
|
|
BinaryOperations[INDEX2(And, Register, Register)] = CAST2(andRR);
|
2008-03-10 22:37:21 +00:00
|
|
|
BinaryOperations[INDEX2(And, Constant, Register)] = CAST2(andCR);
|
|
|
|
BinaryOperations[INDEX2(And, Constant, Memory)] = CAST2(andCM);
|
2008-03-13 20:50:56 +00:00
|
|
|
|
2008-04-28 15:53:48 +00:00
|
|
|
BinaryOperations[INDEX2(Or, Register, Register)] = CAST2(orRR);
|
2008-04-29 23:16:53 +00:00
|
|
|
BinaryOperations[INDEX2(Or, Constant, Register)] = CAST2(orCR);
|
2008-04-28 15:53:48 +00:00
|
|
|
|
2008-04-20 22:19:11 +00:00
|
|
|
BinaryOperations[INDEX2(Xor, Register, Register)] = CAST2(xorRR);
|
2008-04-27 20:42:57 +00:00
|
|
|
BinaryOperations[INDEX2(Xor, Constant, Register)] = CAST2(xorCR);
|
2008-04-20 22:19:11 +00:00
|
|
|
|
2008-04-28 15:53:48 +00:00
|
|
|
BinaryOperations[INDEX2(ShiftLeft, Register, Register)] = CAST2(shiftLeftRR);
|
2008-04-20 00:43:12 +00:00
|
|
|
BinaryOperations[INDEX2(ShiftLeft, Constant, Register)] = CAST2(shiftLeftCR);
|
|
|
|
|
2008-04-28 15:53:48 +00:00
|
|
|
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);
|
|
|
|
|
2008-03-13 20:50:56 +00:00
|
|
|
BinaryOperations[INDEX2(Subtract, Constant, Register)] = CAST2(subtractCR);
|
2008-03-15 23:54:20 +00:00
|
|
|
BinaryOperations[INDEX2(Subtract, Register, Register)] = CAST2(subtractRR);
|
2008-03-13 20:50:56 +00:00
|
|
|
|
2008-06-12 16:56:48 +00:00
|
|
|
BinaryOperations[INDEX2(LongCompare, Constant, Register)]
|
|
|
|
= CAST2(longCompareCR);
|
2008-06-12 17:23:20 +00:00
|
|
|
BinaryOperations[INDEX2(LongCompare, Register, Register)]
|
|
|
|
= CAST2(longCompareRR);
|
2008-06-12 16:56:48 +00:00
|
|
|
|
2008-03-13 23:43:11 +00:00
|
|
|
BinaryOperations[INDEX2(Compare, Constant, Register)] = CAST2(compareCR);
|
2008-04-29 23:16:53 +00:00
|
|
|
BinaryOperations[INDEX2(Compare, Register, Constant)] = CAST2(compareRC);
|
2008-03-15 23:54:20 +00:00
|
|
|
BinaryOperations[INDEX2(Compare, Register, Register)] = CAST2(compareRR);
|
2008-05-19 16:39:05 +00:00
|
|
|
BinaryOperations[INDEX2(Compare, Address, Register)] = CAST2(compareAR);
|
2008-07-31 13:53:43 +00:00
|
|
|
BinaryOperations[INDEX2(Compare, Address, Memory)] = CAST2(compareAM);
|
2008-03-15 23:54:20 +00:00
|
|
|
BinaryOperations[INDEX2(Compare, Register, Memory)] = CAST2(compareRM);
|
2008-04-19 00:19:45 +00:00
|
|
|
BinaryOperations[INDEX2(Compare, Memory, Register)] = CAST2(compareMR);
|
2008-03-13 20:50:56 +00:00
|
|
|
BinaryOperations[INDEX2(Compare, Constant, Memory)] = CAST2(compareCM);
|
2008-03-15 23:54:20 +00:00
|
|
|
BinaryOperations[INDEX2(Compare, Memory, Memory)] = CAST2(compareMM);
|
2008-02-12 00:20:32 +00:00
|
|
|
}
|
|
|
|
|
2008-02-08 23:18:57 +00:00
|
|
|
class MyAssembler: public Assembler {
|
|
|
|
public:
|
2008-02-12 00:20:32 +00:00
|
|
|
MyAssembler(System* s, Allocator* a, Zone* zone): c(s, a, zone) {
|
|
|
|
static bool populated = false;
|
|
|
|
if (not populated) {
|
|
|
|
populated = true;
|
|
|
|
populateTables();
|
|
|
|
}
|
|
|
|
}
|
2008-02-08 23:18:57 +00:00
|
|
|
|
2008-03-13 23:43:11 +00:00
|
|
|
virtual void setClient(Client* client) {
|
|
|
|
assert(&c, c.client == 0);
|
|
|
|
c.client = client;
|
|
|
|
}
|
|
|
|
|
2008-02-08 23:18:57 +00:00
|
|
|
virtual unsigned registerCount() {
|
2008-02-17 20:57:40 +00:00
|
|
|
return 8;//BytesPerWord == 4 ? 8 : 16;
|
2008-02-08 23:18:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual int base() {
|
|
|
|
return rbp;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual int stack() {
|
|
|
|
return rsp;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual int thread() {
|
|
|
|
return rbx;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual int returnLow() {
|
|
|
|
return rax;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual int returnHigh() {
|
|
|
|
return (BytesPerWord == 4 ? rdx : NoRegister);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual unsigned argumentRegisterCount() {
|
|
|
|
return (BytesPerWord == 4 ? 0 : 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual int argumentRegister(unsigned index) {
|
2008-02-12 00:20:32 +00:00
|
|
|
assert(&c, BytesPerWord == 8);
|
2008-02-08 23:18:57 +00:00
|
|
|
|
|
|
|
switch (index) {
|
|
|
|
case 0:
|
|
|
|
return rdi;
|
|
|
|
case 1:
|
|
|
|
return rsi;
|
|
|
|
case 2:
|
|
|
|
return rdx;
|
|
|
|
case 3:
|
|
|
|
return rcx;
|
|
|
|
case 4:
|
|
|
|
return r8;
|
|
|
|
case 5:
|
|
|
|
return r9;
|
|
|
|
default:
|
2008-02-12 00:20:32 +00:00
|
|
|
abort(&c);
|
2008-02-08 23:18:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
virtual void plan(UnaryOperation op, unsigned size, uint8_t* typeMask,
|
2008-05-31 22:14:27 +00:00
|
|
|
uint64_t* registerMask, bool* thunk)
|
2008-02-08 23:18:57 +00:00
|
|
|
{
|
2008-05-04 19:09:12 +00:00
|
|
|
if (op == Negate and BytesPerWord == 4 and size == 8) {
|
|
|
|
*typeMask = 1 << RegisterOperand;
|
|
|
|
*registerMask = (static_cast<uint64_t>(1) << (rdx + 32))
|
|
|
|
| (static_cast<uint64_t>(1) << rax);
|
|
|
|
} else {
|
|
|
|
*typeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
|
|
|
|
*registerMask = ~static_cast<uint64_t>(0);
|
|
|
|
}
|
2008-05-31 22:14:27 +00:00
|
|
|
*thunk = false;
|
2008-05-04 19:09:12 +00:00
|
|
|
}
|
|
|
|
|
2008-05-06 21:13:02 +00:00
|
|
|
virtual void plan(BinaryOperation op, unsigned size, uint8_t* aTypeMask,
|
2008-05-04 19:09:12 +00:00
|
|
|
uint64_t* aRegisterMask, uint8_t* bTypeMask,
|
2008-05-31 22:14:27 +00:00
|
|
|
uint64_t* bRegisterMask, bool* thunk)
|
2008-05-04 19:09:12 +00:00
|
|
|
{
|
2008-05-19 13:27:05 +00:00
|
|
|
*aTypeMask = ~0;
|
2008-05-04 19:09:12 +00:00
|
|
|
*aRegisterMask = ~static_cast<uint64_t>(0);
|
|
|
|
|
|
|
|
*bTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
|
|
|
|
*bRegisterMask = ~static_cast<uint64_t>(0);
|
|
|
|
|
2008-05-31 22:14:27 +00:00
|
|
|
*thunk = false;
|
2008-04-28 22:08:31 +00:00
|
|
|
|
|
|
|
switch (op) {
|
2008-05-19 13:27:05 +00:00
|
|
|
case Compare:
|
|
|
|
if (BytesPerWord == 8 and size != 8) {
|
|
|
|
*aTypeMask = ~(1 << MemoryOperand);
|
|
|
|
*bTypeMask = ~(1 << MemoryOperand);
|
|
|
|
} else {
|
2008-05-19 13:43:37 +00:00
|
|
|
*bTypeMask = ~(1 << ConstantOperand);
|
2008-05-19 13:27:05 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
case Move:
|
|
|
|
if (BytesPerWord == 4 and size == 1) {
|
|
|
|
const uint32_t mask
|
|
|
|
= (1 << rax) | (1 << rcx) | (1 << rdx) | (1 << rbx);
|
|
|
|
*aRegisterMask = (static_cast<uint64_t>(mask) << 32) | mask;
|
|
|
|
*bRegisterMask = (static_cast<uint64_t>(mask) << 32) | mask;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Move4To8:
|
|
|
|
if (BytesPerWord == 4) {
|
|
|
|
const uint32_t mask = ~((1 << rax) | (1 << rdx));
|
|
|
|
*aRegisterMask = (static_cast<uint64_t>(mask) << 32) | mask;
|
|
|
|
*bRegisterMask = (static_cast<uint64_t>(1) << (rdx + 32))
|
|
|
|
| (static_cast<uint64_t>(1) << rax);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-04-29 22:11:17 +00:00
|
|
|
case Multiply:
|
2008-05-04 19:09:12 +00:00
|
|
|
if (BytesPerWord == 4 and size == 8) {
|
|
|
|
const uint32_t mask = ~((1 << rax) | (1 << rdx));
|
|
|
|
*aRegisterMask = (static_cast<uint64_t>(mask) << 32) | mask;
|
|
|
|
*bRegisterMask = (static_cast<uint64_t>(1) << (rdx + 32)) | mask;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-04-28 22:08:31 +00:00
|
|
|
case Divide:
|
2008-05-04 19:09:12 +00:00
|
|
|
if (BytesPerWord == 4 and size == 8) {
|
2008-05-19 13:27:05 +00:00
|
|
|
*bTypeMask = ~0;
|
2008-05-31 22:14:27 +00:00
|
|
|
*thunk = true;
|
2008-05-04 19:09:12 +00:00
|
|
|
} else {
|
|
|
|
*aRegisterMask = ~((1 << rax) | (1 << rdx));
|
|
|
|
*bRegisterMask = 1 << rax;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-04-28 22:08:31 +00:00
|
|
|
case Remainder:
|
|
|
|
if (BytesPerWord == 4 and size == 8) {
|
2008-05-19 13:27:05 +00:00
|
|
|
*bTypeMask = ~0;
|
2008-05-31 22:14:27 +00:00
|
|
|
*thunk = true;
|
2008-05-04 19:09:12 +00:00
|
|
|
} else {
|
|
|
|
*aRegisterMask = ~((1 << rax) | (1 << rdx));
|
|
|
|
*bRegisterMask = 1 << rax;
|
2008-04-28 22:08:31 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-05-04 19:09:12 +00:00
|
|
|
case ShiftLeft:
|
|
|
|
case ShiftRight:
|
2008-05-06 21:13:02 +00:00
|
|
|
case UnsignedShiftRight: {
|
2008-05-18 15:43:31 +00:00
|
|
|
*aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand);
|
2008-05-18 03:32:14 +00:00
|
|
|
*aRegisterMask = (~static_cast<uint64_t>(0) << 32)
|
|
|
|
| (static_cast<uint64_t>(1) << rcx);
|
2008-05-04 19:09:12 +00:00
|
|
|
const uint32_t mask = ~(1 << rcx);
|
|
|
|
*bRegisterMask = (static_cast<uint64_t>(mask) << 32) | mask;
|
2008-05-06 21:13:02 +00:00
|
|
|
} break;
|
2008-05-04 19:09:12 +00:00
|
|
|
|
2008-04-28 22:08:31 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2008-02-08 23:18:57 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
virtual void apply(Operation op) {
|
|
|
|
Operations[op](&c);
|
2008-02-08 23:18:57 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
virtual void apply(UnaryOperation op, unsigned size,
|
|
|
|
OperandType type, Operand* operand)
|
2008-02-08 23:18:57 +00:00
|
|
|
{
|
2008-02-12 00:20:32 +00:00
|
|
|
UnaryOperations[INDEX1(op, type)](&c, size, operand);
|
2008-02-08 23:18:57 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
virtual void apply(BinaryOperation op, unsigned size,
|
|
|
|
OperandType aType, Operand* a,
|
|
|
|
OperandType bType, Operand* b)
|
2008-02-08 23:18:57 +00:00
|
|
|
{
|
2008-02-12 00:20:32 +00:00
|
|
|
BinaryOperations[INDEX2(op, aType, bType)](&c, size, a, b);
|
2008-02-08 23:18:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void writeTo(uint8_t* dst) {
|
2008-02-12 00:20:32 +00:00
|
|
|
c.result = dst;
|
|
|
|
memcpy(dst, c.code.data, c.code.length());
|
2008-02-08 23:18:57 +00:00
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
for (Task* t = c.tasks; t; t = t->next) {
|
|
|
|
t->run(&c);
|
2008-02-08 23:18:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-09 20:11:37 +00:00
|
|
|
virtual unsigned length() {
|
2008-02-12 00:20:32 +00:00
|
|
|
return c.code.length();
|
2008-02-09 20:11:37 +00:00
|
|
|
}
|
|
|
|
|
2008-11-29 23:08:14 +00:00
|
|
|
virtual void updateCall(UnaryOperation op UNUSED,
|
|
|
|
bool assertAlignment UNUSED, void* returnAddress,
|
|
|
|
void* newTarget)
|
|
|
|
{
|
2008-06-02 13:49:09 +00:00
|
|
|
uint8_t* instruction = static_cast<uint8_t*>(returnAddress) - 5;
|
2008-11-29 23:08:14 +00:00
|
|
|
assert(&c, (op == LongCall and *instruction == 0xE8)
|
|
|
|
or (op == LongJump and *instruction == 0xE9));
|
|
|
|
assert(&c, (not assertAlignment)
|
|
|
|
or reinterpret_cast<uintptr_t>(instruction + 1) % 4 == 0);
|
2008-02-09 20:11:37 +00:00
|
|
|
|
2008-06-02 13:49:09 +00:00
|
|
|
int32_t v = static_cast<uint8_t*>(newTarget)
|
|
|
|
- static_cast<uint8_t*>(returnAddress);
|
|
|
|
memcpy(instruction + 1, &v, 4);
|
2008-02-09 20:11:37 +00:00
|
|
|
}
|
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
virtual void dispose() {
|
2008-02-12 00:20:32 +00:00
|
|
|
c.code.dispose();
|
2008-02-11 17:21:41 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
Context c;
|
2008-02-08 23:18:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace vm {
|
|
|
|
|
|
|
|
Assembler*
|
2008-02-09 20:11:37 +00:00
|
|
|
makeAssembler(System* system, Allocator* allocator, Zone* zone)
|
2008-02-08 23:18:57 +00:00
|
|
|
{
|
|
|
|
return new (zone->allocate(sizeof(MyAssembler)))
|
2008-02-12 00:20:32 +00:00
|
|
|
MyAssembler(system, allocator, zone);
|
2008-02-08 23:18:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace vm
|