corda/src/compiler.cpp

1022 lines
22 KiB
C++
Raw Normal View History

2007-12-08 23:22:13 +00:00
#include "compiler.h"
2007-12-09 20:03:21 +00:00
#include "vector.h"
2007-12-11 00:48:09 +00:00
#include "zone.h"
2007-12-08 23:22:13 +00:00
using namespace vm;
namespace {
2007-12-09 22:45:43 +00:00
enum Register {
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,
};
2007-12-11 00:48:09 +00:00
const unsigned RegisterCount32 = 8;
const unsigned RegisterCount64 = 16;
2007-12-09 20:03:21 +00:00
2007-12-11 00:48:09 +00:00
inline bool
isInt8(intptr_t v)
2007-12-09 20:03:21 +00:00
{
2007-12-11 00:48:09 +00:00
return v == static_cast<int8_t>(v);
2007-12-09 20:03:21 +00:00
}
2007-12-11 00:48:09 +00:00
inline bool
isInt32(intptr_t v)
2007-12-09 20:03:21 +00:00
{
2007-12-11 00:48:09 +00:00
return v == static_cast<int32_t>(v);
2007-12-09 20:03:21 +00:00
}
2007-12-11 00:48:09 +00:00
class IpMapping {
public:
IpMapping(unsigned ip, unsigned start): ip(ip), start(start), end(-1) { }
const int ip;
const int start;
int end;
int offset;
};
int
compareIpMappingPointers(const void* a, const void* b)
2007-12-09 20:03:21 +00:00
{
2007-12-11 00:48:09 +00:00
return (*static_cast<IpMapping* const*>(a))->ip
- (*static_cast<IpMapping* const*>(b))->ip;
2007-12-09 20:03:21 +00:00
}
2007-12-08 23:22:13 +00:00
class MyPromise: public Promise {
public:
2007-12-09 20:03:21 +00:00
MyPromise(intptr_t value): resolved(false), value_(value) { }
2007-12-08 23:22:13 +00:00
bool resolved;
2007-12-09 20:03:21 +00:00
intptr_t value_;
};
class PoolPromise: public MyPromise {
public:
PoolPromise(intptr_t value): MyPromise(value) { }
2007-12-11 00:48:09 +00:00
virtual unsigned value(Compiler*);
2007-12-09 20:03:21 +00:00
};
class CodePromise: public MyPromise {
public:
2007-12-09 22:45:43 +00:00
CodePromise(intptr_t value): MyPromise(value) { }
2007-12-09 20:03:21 +00:00
2007-12-11 00:48:09 +00:00
virtual unsigned value(Compiler*);
2007-12-09 20:03:21 +00:00
};
class IpPromise: public MyPromise {
public:
2007-12-09 22:45:43 +00:00
IpPromise(intptr_t value): MyPromise(value) { }
2007-12-09 20:03:21 +00:00
2007-12-11 00:48:09 +00:00
virtual unsigned value(Compiler*);
2007-12-09 20:03:21 +00:00
};
2007-12-11 00:48:09 +00:00
class Context;
class ImmediateOperand;
class RegisterOperand;
class MemoryOperand;
class StackOperand;
void NO_RETURN abort(Context*);
#ifndef NDEBUG
void assert(Context*, bool);
#endif // not NDEBUG
2007-12-09 20:03:21 +00:00
class MyOperand: public Operand {
public:
2007-12-11 00:48:09 +00:00
enum Operation {
push,
pop,
call,
alignedCall,
ret,
mov,
cmp,
jl,
jg,
jle,
jge,
je,
jne,
jmp,
add,
sub,
mul,
div,
rem,
shl,
shr,
ushr,
and_,
or_,
xor_,
neg
2007-12-09 20:03:21 +00:00
};
virtual ~MyOperand() { }
virtual unsigned footprint() {
return BytesPerWord;
}
2007-12-11 00:48:09 +00:00
virtual StackOperand* logicalPush(Context* c) { abort(c); }
2007-12-09 20:03:21 +00:00
2007-12-11 00:48:09 +00:00
virtual void logicalFlush(Context*, StackOperand*) { /* ignore */ }
2007-12-09 22:45:43 +00:00
2007-12-11 00:48:09 +00:00
virtual Register asRegister(Context* c) { abort(c); }
2007-12-09 22:45:43 +00:00
2007-12-11 00:48:09 +00:00
virtual void release(Context*) { /* ignore */ }
2007-12-09 20:03:21 +00:00
2007-12-11 00:48:09 +00:00
virtual void setAbsolute(Context* c, intptr_t) { abort(c); }
2007-12-09 20:03:21 +00:00
2007-12-11 00:48:09 +00:00
virtual void apply(Context* c, Operation) { abort(c); }
2007-12-09 20:03:21 +00:00
2007-12-11 00:48:09 +00:00
virtual void apply(Context* c, Operation, MyOperand*) { abort(c); }
2007-12-09 20:03:21 +00:00
2007-12-11 00:48:09 +00:00
virtual void accept(Context* c, Operation, RegisterOperand*) { abort(c); }
2007-12-09 20:03:21 +00:00
2007-12-11 00:48:09 +00:00
virtual void accept(Context* c, Operation, ImmediateOperand*) { abort(c); }
2007-12-09 20:03:21 +00:00
2007-12-11 00:48:09 +00:00
virtual void accept(Context* c, Operation, MemoryOperand*) { abort(c); }
2007-12-09 20:03:21 +00:00
};
2007-12-11 00:48:09 +00:00
class StackOperand;
2007-12-09 20:03:21 +00:00
class RegisterOperand: public MyOperand {
public:
RegisterOperand(Register value):
2007-12-11 00:48:09 +00:00
value(value), reserved(false), stack(0)
2007-12-09 20:03:21 +00:00
{ }
2007-12-11 00:48:09 +00:00
virtual void logicalFlush(Context* c UNUSED, StackOperand* s UNUSED) {
assert(c, stack == s);
stack = 0;
2007-12-09 20:03:21 +00:00
}
2007-12-11 00:48:09 +00:00
virtual void release(Context* c UNUSED) {
assert(c, reserved);
reserved = false;
2007-12-09 20:03:21 +00:00
}
2007-12-11 00:48:09 +00:00
virtual void apply(Context* c, Operation) { abort(c); }
2007-12-09 20:03:21 +00:00
2007-12-11 00:48:09 +00:00
virtual void apply(Context* c, Operation operation, MyOperand* operand) {
operand->accept(c, operation, this);
2007-12-09 20:03:21 +00:00
}
Register value;
2007-12-11 00:48:09 +00:00
bool reserved;
StackOperand* stack;
2007-12-08 23:22:13 +00:00
};
2007-12-09 22:45:43 +00:00
class ImmediateOperand: public MyOperand {
public:
ImmediateOperand(intptr_t value):
value(value)
{ }
2007-12-09 20:03:21 +00:00
2007-12-11 00:48:09 +00:00
virtual void apply(Context* c, Operation) { abort(c); }
2007-12-09 22:45:43 +00:00
2007-12-11 00:48:09 +00:00
virtual void apply(Context* c, Operation operation, MyOperand* operand) {
operand->accept(c, operation, this);
2007-12-09 22:45:43 +00:00
}
intptr_t value;
};
class AbsoluteOperand: public MyOperand {
public:
2007-12-11 00:48:09 +00:00
AbsoluteOperand(MyPromise* value):
2007-12-09 22:45:43 +00:00
value(value)
{ }
2007-12-11 00:48:09 +00:00
virtual void setAbsolute(Context*, intptr_t v) {
value->value_ = v;
2007-12-09 22:45:43 +00:00
}
2007-12-11 00:48:09 +00:00
MyPromise* value;
2007-12-09 22:45:43 +00:00
};
2007-12-09 20:03:21 +00:00
class MemoryOperand: public MyOperand {
public:
MemoryOperand(MyOperand* base, int displacement, MyOperand* index,
unsigned scale):
base(base),
displacement(displacement),
index(index),
scale(scale)
{ }
2007-12-11 00:48:09 +00:00
virtual void apply(Context* c, Operation operation, MyOperand* operand) {
operand->accept(c, operation, this);
2007-12-09 20:03:21 +00:00
}
MyOperand* base;
int displacement;
MyOperand* index;
unsigned scale;
};
class SelectionOperand: public MyOperand {
public:
2007-12-09 22:45:43 +00:00
enum SelectionType {
S1Selection,
S2Selection,
Z2Selection,
S4Selection,
S8Selection
};
SelectionOperand(SelectionType type, MyOperand* base):
selectionType(type), base(base)
2007-12-09 20:03:21 +00:00
{ }
virtual unsigned footprint() {
2007-12-09 22:45:43 +00:00
if (selectionType == S8Selection) {
2007-12-09 20:03:21 +00:00
return 8;
} else {
return 4;
}
}
2007-12-11 00:48:09 +00:00
SelectionType selectionType;
MyOperand* base;
};
class StackOperand: public MyOperand {
public:
StackOperand(MyOperand* base, StackOperand* next):
base(base), next(next), flushed(false)
{
if (next) {
index = next->index + (next->footprint() / BytesPerWord);
} else {
index = 0;
}
2007-12-09 20:03:21 +00:00
}
MyOperand* base;
2007-12-11 00:48:09 +00:00
StackOperand* next;
int index;
bool flushed;
2007-12-09 20:03:21 +00:00
};
2007-12-11 00:48:09 +00:00
class Context {
public:
Context(System* s, void* indirectCaller):
s(s),
code(s, 1024),
constantPool(s, BytesPerWord * 32),
ipMappings(s, 1024),
zone(s, 8 * 1024),
indirectCaller(reinterpret_cast<intptr_t>(indirectCaller)),
stack(0),
machineTable(0),
logicalTable(0)
{
for (unsigned i = 0; i < RegisterCount64; ++i) {
registers[i] = new (zone.allocate(sizeof(RegisterOperand)))
RegisterOperand(static_cast<Register>(i));
}
registers[rsp]->reserved = true;
registers[rbp]->reserved = true;
registers[rbx]->reserved = true;
}
void dispose() {
zone.dispose();
ipMappings.dispose();
constantPool.dispose();
code.dispose();
if (machineTable) s->free(machineTable);
if (logicalTable) s->free(logicalTable);
}
System* s;
Vector code;
Vector constantPool;
Vector ipMappings;
Zone zone;
intptr_t indirectCaller;
StackOperand* stack;
IpMapping** machineTable;
IpMapping** logicalTable;
RegisterOperand* registers[RegisterCount64];
};
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);
}
2007-12-09 20:03:21 +00:00
ImmediateOperand*
immediate(Context* c, intptr_t v)
{
2007-12-11 00:48:09 +00:00
return new (c->zone.allocate(sizeof(ImmediateOperand))) ImmediateOperand(v);
2007-12-09 20:03:21 +00:00
}
AbsoluteOperand*
2007-12-11 00:48:09 +00:00
absolute(Context* c, MyPromise* v)
2007-12-09 20:03:21 +00:00
{
2007-12-11 00:48:09 +00:00
return new (c->zone.allocate(sizeof(AbsoluteOperand))) AbsoluteOperand(v);
2007-12-09 20:03:21 +00:00
}
RegisterOperand*
register_(Context* c, Register v)
{
2007-12-11 00:48:09 +00:00
return c->registers[v];
2007-12-09 20:03:21 +00:00
}
MemoryOperand*
memory(Context* c, MyOperand* base, int displacement,
MyOperand* index, unsigned scale)
{
2007-12-11 00:48:09 +00:00
return new (c->zone.allocate(sizeof(MemoryOperand)))
MemoryOperand(base, displacement, index, scale);
2007-12-09 20:03:21 +00:00
}
2007-12-11 00:48:09 +00:00
void
flush(Context* c, StackOperand* s)
2007-12-09 20:03:21 +00:00
{
2007-12-11 00:48:09 +00:00
s->base->apply(c, MyOperand::push);
s->base->logicalFlush(c, s);
s->base = memory
(c, register_(c, rbp), - (s->index + 1) * BytesPerWord, 0, 1);
s->flushed = true;
}
RegisterOperand*
temporary(Context* c)
{
RegisterOperand* r = 0;
for (unsigned i = 0; i < RegisterCount32; ++i) {
if (not c->registers[i]->reserved) {
if (not c->registers[i]->stack) {
c->registers[i]->reserved = true;
return c->registers[i];
} else if (r == 0 or r->stack->index > c->registers[i]->stack->index) {
r = c->registers[i];
}
}
}
if (r) {
flush(c, r->stack);
return r;
} else {
abort(c);
}
}
void
release(Context* c UNUSED, RegisterOperand* v)
{
assert(c, v->reserved);
v->reserved = false;
}
StackOperand*
push(Context* c, MyOperand* base)
{
return base->logicalPush(c);
}
void
pop(Context* c, MyOperand* dst)
{
if (c->stack->flushed) {
dst->apply(c, MyOperand::pop);
} else {
c->stack->base->apply(c, MyOperand::mov, dst);
}
c->stack = c->stack->next;
}
MyOperand*
pop(Context* c)
{
if (c->stack->flushed) {
RegisterOperand* tmp = temporary(c);
tmp->apply(c, MyOperand::pop);
return tmp;
} else {
return c->stack->base;
}
c->stack = c->stack->next;
2007-12-09 20:03:21 +00:00
}
MyOperand*
2007-12-09 22:45:43 +00:00
selection(Context* c, SelectionOperand::SelectionType type, MyOperand* base)
2007-12-09 20:03:21 +00:00
{
2007-12-09 22:45:43 +00:00
if ((type == SelectionOperand::S4Selection and BytesPerWord == 4)
or (type == SelectionOperand::S8Selection and BytesPerWord == 8))
2007-12-09 20:03:21 +00:00
{
return base;
} else {
2007-12-11 00:48:09 +00:00
return new (c->zone.allocate(sizeof(SelectionOperand)))
SelectionOperand(type, base);
2007-12-09 20:03:21 +00:00
}
}
void
flushStack(Context* c)
{
2007-12-11 00:48:09 +00:00
if (c->stack) {
StackOperand* stack[c->stack->index + 1];
int index = c->stack->index + 1;
for (StackOperand* s = c->stack; s and not s->flushed; s = s->next) {
stack[-- index] = s;
}
for (; index < c->stack->index + 1; ++ index) {
flush(c, stack[index]);
}
2007-12-09 20:03:21 +00:00
}
}
2007-12-09 20:03:21 +00:00
Register
gpRegister(Context* c, unsigned index)
{
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:
abort(c);
}
2007-12-09 22:45:43 +00:00
}
unsigned
pushArguments(Context* c, unsigned count, va_list list)
{
flushStack(c);
2007-12-09 22:45:43 +00:00
MyOperand* arguments[count];
unsigned footprint = 0;
for (unsigned i = 0; i < count; ++i) {
arguments[i] = va_arg(list, MyOperand*);
footprint += pad(arguments[i]->footprint());
}
const int GprCount = 6;
2007-12-09 22:45:43 +00:00
for (int i = count - 1; i >= 0; --i) {
if (BytesPerWord == 8 and i < GprCount) {
2007-12-11 00:48:09 +00:00
arguments[i]->apply(c, MyOperand::mov, register_(c, gpRegister(c, i)));
} else {
2007-12-11 00:48:09 +00:00
arguments[i]->apply(c, MyOperand::push);
}
2007-12-09 22:45:43 +00:00
}
if (BytesPerWord == 8) {
if (footprint > GprCount * BytesPerWord) {
return footprint - GprCount * BytesPerWord;
} else {
return 0;
}
} else {
return footprint;
}
2007-12-09 20:03:21 +00:00
}
2007-12-11 00:48:09 +00:00
void
rex(Context* c)
{
if (BytesPerWord == 8) {
c->code.append(0x48);
}
}
void
ret(Context* c)
{
c->code.append(0xc3);
}
void
encode(Context* c, uint8_t instruction, uint8_t zeroPrefix,
uint8_t bytePrefix, uint8_t wordPrefix,
Register a, Register b, int32_t offset)
{
c->code.append(instruction);
uint8_t prefix;
if (offset == 0 and b != rbp) {
prefix = zeroPrefix;
} else if (isInt8(offset)) {
prefix = bytePrefix;
} else {
prefix = wordPrefix;
}
c->code.append(prefix | (a << 3) | b);
if (b == rsp) {
c->code.append(0x24);
}
if (offset == 0 and b != rbp) {
// do nothing
} else if (isInt8(offset)) {
c->code.append(offset);
} else {
c->code.append4(offset);
}
}
2007-12-08 23:22:13 +00:00
class MyCompiler: public Compiler {
public:
MyCompiler(System* s, void* indirectCaller):
2007-12-09 20:03:21 +00:00
c(s, indirectCaller)
2007-12-08 23:22:13 +00:00
{ }
virtual Promise* poolOffset() {
2007-12-11 00:48:09 +00:00
return new (c.zone.allocate(sizeof(PoolPromise)))
PoolPromise(c.constantPool.length());
2007-12-08 23:22:13 +00:00
}
virtual Promise* codeOffset() {
2007-12-11 00:48:09 +00:00
return new (c.zone.allocate(sizeof(CodePromise)))
CodePromise(c.code.length());
2007-12-08 23:22:13 +00:00
}
virtual Operand* poolAppend(Operand* v) {
2007-12-11 00:48:09 +00:00
Operand* r = absolute(&c, static_cast<MyPromise*>(poolOffset()));
c.constantPool.appendAddress(v);
2007-12-08 23:22:13 +00:00
return r;
}
virtual Operand* constant(intptr_t v) {
2007-12-09 20:03:21 +00:00
return immediate(&c, v);
2007-12-08 23:22:13 +00:00
}
virtual void push(Operand* v) {
2007-12-11 00:48:09 +00:00
::push(&c, static_cast<MyOperand*>(v));
2007-12-08 23:22:13 +00:00
}
virtual void push2(Operand* v) {
2007-12-09 20:03:21 +00:00
push(v);
if (BytesPerWord == 8) push(immediate(&c, 0));
2007-12-08 23:22:13 +00:00
}
virtual Operand* stack(unsigned index) {
2007-12-11 00:48:09 +00:00
StackOperand* s = c.stack;
unsigned i = 0;
if (s->footprint() / BytesPerWord == 2) ++ i;
for (; i < index; ++i) {
s = s->next;
if (s->footprint() / BytesPerWord == 2) ++ i;
}
2007-12-08 23:22:13 +00:00
2007-12-11 00:48:09 +00:00
return s;
2007-12-08 23:22:13 +00:00
}
virtual Operand* pop() {
2007-12-11 00:48:09 +00:00
return ::pop(&c);
2007-12-08 23:22:13 +00:00
}
virtual Operand* pop2() {
2007-12-09 20:03:21 +00:00
if (BytesPerWord == 8) pop();
return pop();
2007-12-08 23:22:13 +00:00
}
virtual void pop(Operand* dst) {
2007-12-11 00:48:09 +00:00
::pop(&c, static_cast<MyOperand*>(dst));
2007-12-08 23:22:13 +00:00
}
virtual void pop2(Operand* dst) {
2007-12-09 20:03:21 +00:00
if (BytesPerWord == 8) pop();
pop(dst);
2007-12-08 23:22:13 +00:00
}
virtual Operand* stack() {
2007-12-09 20:03:21 +00:00
flushStack(&c);
return register_(&c, rsp);
2007-12-08 23:22:13 +00:00
}
virtual Operand* base() {
2007-12-09 20:03:21 +00:00
return register_(&c, rbp);
2007-12-08 23:22:13 +00:00
}
virtual Operand* thread() {
2007-12-09 20:03:21 +00:00
return register_(&c, rbx);
2007-12-08 23:22:13 +00:00
}
virtual Operand* indirectTarget() {
2007-12-09 20:03:21 +00:00
return register_(&c, rax);
2007-12-08 23:22:13 +00:00
}
virtual Operand* temporary() {
2007-12-09 20:03:21 +00:00
return ::temporary(&c);
2007-12-08 23:22:13 +00:00
}
virtual void release(Operand* v) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->release(&c);
2007-12-08 23:22:13 +00:00
}
virtual Operand* label() {
2007-12-11 00:48:09 +00:00
return absolute
(&c, new (c.zone.allocate(sizeof(CodePromise))) CodePromise(0));
2007-12-08 23:22:13 +00:00
}
virtual void mark(Operand* label) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(label)->setAbsolute(&c, c.code.length());
2007-12-08 23:22:13 +00:00
}
virtual Operand* indirectCall
(Operand* address, unsigned argumentCount, ...)
{
va_list a; va_start(a, argumentCount);
2007-12-09 22:45:43 +00:00
unsigned footprint = pushArguments(&c, argumentCount, a);
2007-12-08 23:22:13 +00:00
va_end(a);
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(address)->apply
(&c, MyOperand::mov, register_(&c, rax));
2007-12-08 23:22:13 +00:00
2007-12-11 00:48:09 +00:00
immediate(&c, c.indirectCaller)->apply(&c, MyOperand::call);
immediate(&c, footprint)->apply(&c, MyOperand::sub, register_(&c, rsp));
2007-12-09 22:45:43 +00:00
return register_(&c, rax);
2007-12-08 23:22:13 +00:00
}
2007-12-09 22:45:43 +00:00
virtual void indirectCallNoReturn
2007-12-08 23:22:13 +00:00
(Operand* address, unsigned argumentCount, ...)
{
va_list a; va_start(a, argumentCount);
2007-12-09 20:03:21 +00:00
pushArguments(&c, argumentCount, a);
2007-12-08 23:22:13 +00:00
va_end(a);
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(address)->apply
(&c, MyOperand::mov, register_(&c, rax));
immediate(&c, c.indirectCaller)->apply(&c, MyOperand::call);
2007-12-08 23:22:13 +00:00
}
virtual Operand* directCall
(Operand* address, unsigned argumentCount, ...)
{
va_list a; va_start(a, argumentCount);
2007-12-09 22:45:43 +00:00
unsigned footprint = pushArguments(&c, argumentCount, a);
2007-12-08 23:22:13 +00:00
va_end(a);
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(address)->apply(&c, MyOperand::call);
2007-12-08 23:22:13 +00:00
2007-12-11 00:48:09 +00:00
immediate(&c, footprint)->apply(&c, MyOperand::sub, register_(&c, rsp));
2007-12-09 22:45:43 +00:00
return register_(&c, rax);
2007-12-08 23:22:13 +00:00
}
virtual void return_(Operand* v) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply(&c, MyOperand::mov, register_(&c, rax));
2007-12-09 22:45:43 +00:00
ret();
2007-12-08 23:22:13 +00:00
}
2007-12-11 00:48:09 +00:00
virtual Operand* call(Operand* v) {
flushStack(&c);
static_cast<MyOperand*>(v)->apply(&c, MyOperand::call);
return register_(&c, rax);
}
virtual Operand* alignedCall(Operand* v) {
flushStack(&c);
static_cast<MyOperand*>(v)->apply(&c, MyOperand::alignedCall);
return register_(&c, rax);
}
2007-12-08 23:22:13 +00:00
virtual void ret() {
2007-12-09 22:45:43 +00:00
::ret(&c);
2007-12-08 23:22:13 +00:00
}
virtual void mov(Operand* src, Operand* dst) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(src)->apply
(&c, MyOperand::mov, static_cast<MyOperand*>(dst));
2007-12-08 23:22:13 +00:00
}
virtual void cmp(Operand* subtrahend, Operand* minuend) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(subtrahend)->apply
(&c, MyOperand::cmp, static_cast<MyOperand*>(minuend));
2007-12-08 23:22:13 +00:00
}
virtual void jl(Operand* v) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply(&c, MyOperand::jl);
2007-12-08 23:22:13 +00:00
}
virtual void jg(Operand* v) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply(&c, MyOperand::jg);
2007-12-08 23:22:13 +00:00
}
virtual void jle(Operand* v) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply(&c, MyOperand::jle);
2007-12-08 23:22:13 +00:00
}
virtual void jge(Operand* v) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply(&c, MyOperand::jge);
2007-12-08 23:22:13 +00:00
}
virtual void je(Operand* v) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply(&c, MyOperand::je);
2007-12-08 23:22:13 +00:00
}
virtual void jne(Operand* v) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply(&c, MyOperand::jne);
2007-12-08 23:22:13 +00:00
}
virtual void jmp(Operand* v) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply(&c, MyOperand::jmp);
2007-12-08 23:22:13 +00:00
}
virtual void add(Operand* v, Operand* dst) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply
(&c, MyOperand::add, static_cast<MyOperand*>(dst));
2007-12-08 23:22:13 +00:00
}
virtual void sub(Operand* v, Operand* dst) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply
(&c, MyOperand::sub, static_cast<MyOperand*>(dst));
2007-12-08 23:22:13 +00:00
}
virtual void mul(Operand* v, Operand* dst) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply
(&c, MyOperand::mul, static_cast<MyOperand*>(dst));
2007-12-08 23:22:13 +00:00
}
virtual void div(Operand* v, Operand* dst) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply
(&c, MyOperand::div, static_cast<MyOperand*>(dst));
2007-12-08 23:22:13 +00:00
}
virtual void rem(Operand* v, Operand* dst) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply
(&c, MyOperand::rem, static_cast<MyOperand*>(dst));
2007-12-08 23:22:13 +00:00
}
virtual void shl(Operand* v, Operand* dst) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply
(&c, MyOperand::shl, static_cast<MyOperand*>(dst));
2007-12-08 23:22:13 +00:00
}
virtual void shr(Operand* v, Operand* dst) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply
(&c, MyOperand::shr, static_cast<MyOperand*>(dst));
2007-12-08 23:22:13 +00:00
}
virtual void ushr(Operand* v, Operand* dst) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply
(&c, MyOperand::ushr, static_cast<MyOperand*>(dst));
2007-12-08 23:22:13 +00:00
}
virtual void and_(Operand* v, Operand* dst) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply
(&c, MyOperand::and_, static_cast<MyOperand*>(dst));
2007-12-08 23:22:13 +00:00
}
virtual void or_(Operand* v, Operand* dst) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply
(&c, MyOperand::or_, static_cast<MyOperand*>(dst));
2007-12-08 23:22:13 +00:00
}
virtual void xor_(Operand* v, Operand* dst) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply
(&c, MyOperand::xor_, static_cast<MyOperand*>(dst));
2007-12-08 23:22:13 +00:00
}
virtual void neg(Operand* v) {
2007-12-11 00:48:09 +00:00
static_cast<MyOperand*>(v)->apply(&c, MyOperand::neg);
2007-12-08 23:22:13 +00:00
}
2007-12-09 20:03:21 +00:00
virtual Operand* memory(Operand* base, int displacement,
2007-12-08 23:22:13 +00:00
Operand* index, unsigned scale)
{
2007-12-09 22:45:43 +00:00
return ::memory(&c, static_cast<MyOperand*>(base), displacement,
static_cast<MyOperand*>(index), scale);
}
virtual Operand* select1(Operand* v) {
return selection(&c, SelectionOperand::S1Selection,
static_cast<MyOperand*>(v));
}
virtual Operand* select2(Operand* v) {
return selection(&c, SelectionOperand::S2Selection,
static_cast<MyOperand*>(v));
}
virtual Operand* select2z(Operand* v) {
return selection(&c, SelectionOperand::Z2Selection,
static_cast<MyOperand*>(v));
}
virtual Operand* select4(Operand* v) {
return selection(&c, SelectionOperand::S4Selection,
static_cast<MyOperand*>(v));
2007-12-08 23:22:13 +00:00
}
2007-12-09 22:45:43 +00:00
virtual Operand* select8(Operand* v) {
return selection(&c, SelectionOperand::S8Selection,
static_cast<MyOperand*>(v));
2007-12-08 23:22:13 +00:00
}
virtual void prologue() {
2007-12-11 00:48:09 +00:00
register_(&c, rbp)->apply(&c, MyOperand::push);
register_(&c, rsp)->apply(&c, MyOperand::mov, register_(&c, rbp));
2007-12-08 23:22:13 +00:00
}
virtual void epilogue() {
2007-12-11 00:48:09 +00:00
register_(&c, rbp)->apply(&c, MyOperand::mov, register_(&c, rsp));
register_(&c, rbp)->apply(&c, MyOperand::push);
2007-12-08 23:22:13 +00:00
}
2007-12-09 20:03:21 +00:00
virtual void startLogicalIp(unsigned ip) {
2007-12-11 00:48:09 +00:00
new (c.ipMappings.allocate(sizeof(IpMapping)))
IpMapping(ip, c.code.length());
2007-12-08 23:22:13 +00:00
}
2007-12-09 20:03:21 +00:00
virtual Operand* logicalIp(unsigned ip) {
2007-12-11 00:48:09 +00:00
return absolute(&c, static_cast<MyPromise*>(logicalIpToOffset(ip)));
2007-12-08 23:22:13 +00:00
}
2007-12-11 00:48:09 +00:00
virtual Promise* logicalIpToOffset(unsigned ip) {
return new (c.zone.allocate(sizeof(IpPromise))) IpPromise(ip);
}
2007-12-08 23:22:13 +00:00
2007-12-11 00:48:09 +00:00
virtual unsigned size() {
return c.code.length() + c.constantPool.length();
}
virtual void writeTo(void* out) {
unsigned tableSize = (c.ipMappings.length() / sizeof(IpMapping));
c.machineTable = static_cast<IpMapping**>
(c.s->allocate(tableSize * BytesPerWord));
c.logicalTable = static_cast<IpMapping**>
(c.s->allocate(tableSize * BytesPerWord));
for (unsigned i = 0; i < tableSize; ++i) {
IpMapping* mapping = c.ipMappings.peek<IpMapping>(i * sizeof(IpMapping));
if (i + 1 < c.ipMappings.length()) {
mapping->end = c.ipMappings.peek<IpMapping>
((i + 1) * sizeof(IpMapping))->start;
} else {
mapping->end = c.code.length();
2007-12-08 23:22:13 +00:00
}
2007-12-11 00:48:09 +00:00
c.machineTable[i] = mapping;
c.logicalTable[i] = mapping;
2007-12-08 23:22:13 +00:00
}
2007-12-11 00:48:09 +00:00
qsort(c.logicalTable, c.ipMappings.length() / sizeof(IpMapping),
BytesPerWord, compareIpMappingPointers);
2007-12-08 23:22:13 +00:00
2007-12-11 00:48:09 +00:00
uint8_t* p = static_cast<uint8_t*>(out);
for (unsigned i = 0; i < tableSize; ++i) {
IpMapping* mapping = c.logicalTable[i];
mapping->offset = (p - static_cast<uint8_t*>(out));
2007-12-08 23:22:13 +00:00
2007-12-11 00:48:09 +00:00
int length = mapping->end - mapping->start;
memcpy(p, c.code.data + mapping->start, length);
p += length;
}
memcpy(p, c.constantPool.data, c.constantPool.length());
2007-12-08 23:22:13 +00:00
}
2007-12-11 00:48:09 +00:00
virtual void updateCall(void* returnAddress, void* newTarget) {
uint8_t* instruction = static_cast<uint8_t*>(returnAddress) - 5;
assert(&c, *instruction == 0xE8);
int32_t v = static_cast<uint8_t*>(newTarget)
- static_cast<uint8_t*>(returnAddress);
memcpy(instruction + 1, &v, 4);
2007-12-09 20:03:21 +00:00
}
2007-12-08 23:22:13 +00:00
virtual void dispose() {
2007-12-09 20:03:21 +00:00
c.dispose();
2007-12-08 23:22:13 +00:00
2007-12-09 22:45:43 +00:00
c.s->free(this);
2007-12-08 23:22:13 +00:00
}
2007-12-09 20:03:21 +00:00
Context c;
2007-12-08 23:22:13 +00:00
};
2007-12-11 00:48:09 +00:00
unsigned
PoolPromise::value(Compiler* compiler)
{
Context* c = &(static_cast<MyCompiler*>(compiler)->c);
if (c->logicalTable) {
return c->code.length() + value_;
}
abort(c);
}
unsigned
CodePromise::value(Compiler* compiler)
{
Context* c = &(static_cast<MyCompiler*>(compiler)->c);
if (c->logicalTable) {
unsigned bottom = 0;
unsigned top = c->ipMappings.length() / sizeof(IpMapping);
for (unsigned span = top - bottom; span; span = top - bottom) {
unsigned middle = bottom + (span / 2);
IpMapping* mapping = c->machineTable[middle];
if (value_ >= mapping->start and value_ < mapping->end) {
return mapping->offset + (value_ - mapping->start);
} else if (value_ < mapping->start) {
top = middle;
} else if (value_ > mapping->start) {
bottom = middle + 1;
}
}
}
abort(c);
}
unsigned
IpPromise::value(Compiler* compiler)
{
Context* c = &(static_cast<MyCompiler*>(compiler)->c);
if (c->logicalTable) {
unsigned bottom = 0;
unsigned top = c->ipMappings.length() / sizeof(IpMapping);
for (unsigned span = top - bottom; span; span = top - bottom) {
unsigned middle = bottom + (span / 2);
IpMapping* mapping = c->logicalTable[middle];
if (value_ == mapping->ip) {
return mapping->start;
} else if (value_ < mapping->ip) {
top = middle;
} else if (value_ > mapping->ip) {
bottom = middle + 1;
}
}
}
abort(c);
}
2007-12-08 23:22:13 +00:00
} // namespace
namespace vm {
Compiler*
makeCompiler(System* system, void* indirectCaller)
{
return new (system->allocate(sizeof(MyCompiler)))
MyCompiler(system, indirectCaller);
}
} // namespace vm