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-14 00:27:09 +00:00
|
|
|
enum SelectionType {
|
|
|
|
S1Selection,
|
|
|
|
S2Selection,
|
|
|
|
Z2Selection,
|
|
|
|
S4Selection,
|
|
|
|
S8Selection
|
|
|
|
};
|
|
|
|
|
2007-12-15 01:11:01 +00:00
|
|
|
const bool Verbose = false;
|
2007-12-14 18:27:56 +00:00
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
const unsigned RegisterCount = BytesPerWord * 2;
|
2007-12-16 00:24:15 +00:00
|
|
|
const unsigned GprParameterCount = 6;
|
2007-12-16 21:30:19 +00:00
|
|
|
const SelectionType DefaultSelection
|
|
|
|
= (BytesPerWord == 8 ? S8Selection : S4Selection);
|
2007-12-11 21:26:59 +00:00
|
|
|
|
|
|
|
class Context;
|
2007-12-16 00:24:15 +00:00
|
|
|
class MyOperand;
|
2007-12-16 21:30:19 +00:00
|
|
|
class AddressOperand;
|
2007-12-11 21:26:59 +00:00
|
|
|
class ImmediateOperand;
|
2007-12-11 23:52:28 +00:00
|
|
|
class AbsoluteOperand;
|
2007-12-11 21:26:59 +00:00
|
|
|
class RegisterOperand;
|
|
|
|
class MemoryOperand;
|
2007-12-14 00:27:09 +00:00
|
|
|
class CodePromise;
|
|
|
|
class MyPromise;
|
2007-12-11 21:26:59 +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-16 00:24:15 +00:00
|
|
|
class RegisterNode {
|
|
|
|
public:
|
|
|
|
RegisterNode(Register value, RegisterNode* next):
|
|
|
|
value(value), next(next)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
Register value;
|
|
|
|
RegisterNode* next;
|
|
|
|
};
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
class Task {
|
2007-12-08 23:22:13 +00:00
|
|
|
public:
|
2007-12-14 00:27:09 +00:00
|
|
|
Task(Task* next): next(next) { }
|
2007-12-08 23:22:13 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
virtual ~Task() { }
|
2007-12-11 23:52:28 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
virtual void run(Context*, unsigned) = 0;
|
2007-12-12 22:19:13 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
Task* next;
|
2007-12-09 20:03:21 +00:00
|
|
|
};
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
class Event {
|
2007-12-12 22:19:13 +00:00
|
|
|
public:
|
2007-12-15 01:11:01 +00:00
|
|
|
Event(Event* next): next(next), task(0) {
|
2007-12-14 00:27:09 +00:00
|
|
|
if (next) {
|
|
|
|
count = next->count + 1;
|
|
|
|
} else {
|
|
|
|
count = 1;
|
|
|
|
}
|
2007-12-12 22:19:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
virtual ~Event() { }
|
2007-12-09 20:03:21 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
virtual void run(Context*) { }
|
2007-12-11 23:52:28 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
Event* next;
|
|
|
|
Task* task;
|
|
|
|
unsigned count;
|
2007-12-11 21:26:59 +00:00
|
|
|
};
|
2007-12-11 00:48:09 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
class Segment {
|
2007-12-11 21:26:59 +00:00
|
|
|
public:
|
2007-12-14 00:27:09 +00:00
|
|
|
Segment(int logicalIp, Event* event):
|
2007-12-15 01:11:01 +00:00
|
|
|
logicalIp(logicalIp), offset(-1), event(event)
|
2007-12-12 22:19:13 +00:00
|
|
|
{ }
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
int logicalIp;
|
2007-12-15 01:11:01 +00:00
|
|
|
int offset;
|
2007-12-14 00:27:09 +00:00
|
|
|
Event* event;
|
2007-12-11 21:26:59 +00:00
|
|
|
};
|
2007-12-11 00:48:09 +00:00
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
class MyStack: public Stack {
|
|
|
|
public:
|
|
|
|
MyStack(MyOperand* value, int index, MyStack* next):
|
|
|
|
value(value), index(index), next(next)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
MyOperand* value;
|
|
|
|
int index;
|
|
|
|
MyStack* next;
|
|
|
|
};
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
class RegisterData {
|
|
|
|
public:
|
|
|
|
RegisterData(): reserved(false) { }
|
|
|
|
|
|
|
|
bool reserved;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Context {
|
|
|
|
public:
|
|
|
|
Context(System* s, void* indirectCaller):
|
|
|
|
s(s),
|
|
|
|
constantPool(s, BytesPerWord * 32),
|
|
|
|
plan(s, 1024),
|
|
|
|
code(s, 1024),
|
|
|
|
zone(s, 8 * 1024),
|
|
|
|
indirectCaller(reinterpret_cast<intptr_t>(indirectCaller)),
|
|
|
|
segmentTable(0),
|
|
|
|
reserved(0),
|
|
|
|
codeLength(-1)
|
|
|
|
{
|
|
|
|
plan.appendAddress(new (zone.allocate(sizeof(Segment))) Segment
|
|
|
|
(-1, new (zone.allocate(sizeof(Event))) Event(0)));
|
|
|
|
|
|
|
|
registers[rsp].reserved = true;
|
|
|
|
registers[rbp].reserved = true;
|
|
|
|
registers[rbx].reserved = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dispose() {
|
|
|
|
zone.dispose();
|
|
|
|
plan.dispose();
|
|
|
|
code.dispose();
|
|
|
|
constantPool.dispose();
|
|
|
|
if (segmentTable) s->free(segmentTable);
|
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
Vector constantPool;
|
|
|
|
Vector plan;
|
|
|
|
Vector code;
|
|
|
|
Zone zone;
|
|
|
|
intptr_t indirectCaller;
|
|
|
|
Segment** segmentTable;
|
|
|
|
unsigned reserved;
|
|
|
|
int codeLength;
|
|
|
|
RegisterData registers[RegisterCount];
|
|
|
|
};
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
class MyPromise: public Promise {
|
|
|
|
public:
|
|
|
|
virtual intptr_t value(Compiler*);
|
|
|
|
|
|
|
|
virtual intptr_t value(Context*) = 0;
|
|
|
|
|
|
|
|
virtual bool resolved(Context*) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ResolvedPromise: public MyPromise {
|
|
|
|
public:
|
|
|
|
ResolvedPromise(intptr_t value): value_(value) { }
|
|
|
|
|
|
|
|
virtual intptr_t value(Context*) {
|
|
|
|
return value_;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool resolved(Context*) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
intptr_t value_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class PoolPromise: public MyPromise {
|
|
|
|
public:
|
|
|
|
PoolPromise(intptr_t key): key(key) { }
|
|
|
|
|
|
|
|
virtual intptr_t value(Context* c) {
|
|
|
|
if (resolved(c)) {
|
|
|
|
return reinterpret_cast<intptr_t>(c->code.data + c->codeLength + key);
|
|
|
|
}
|
|
|
|
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool resolved(Context* c) {
|
|
|
|
return c->codeLength >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
intptr_t key;
|
|
|
|
};
|
|
|
|
|
|
|
|
class CodePromise: public MyPromise {
|
|
|
|
public:
|
|
|
|
CodePromise():
|
|
|
|
offset(-1)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual intptr_t value(Context* c) {
|
|
|
|
if (resolved(c)) {
|
|
|
|
return reinterpret_cast<intptr_t>(c->code.data + offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool resolved(Context*) {
|
|
|
|
return offset >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
intptr_t offset;
|
|
|
|
};
|
|
|
|
|
|
|
|
class IpPromise: public MyPromise {
|
|
|
|
public:
|
|
|
|
IpPromise(intptr_t logicalIp):
|
|
|
|
logicalIp(logicalIp)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual intptr_t value(Context* c) {
|
|
|
|
if (resolved(c)) {
|
|
|
|
unsigned bottom = 0;
|
|
|
|
unsigned top = c->plan.length() / BytesPerWord;
|
|
|
|
for (unsigned span = top - bottom; span; span = top - bottom) {
|
|
|
|
unsigned middle = bottom + (span / 2);
|
|
|
|
Segment* s = c->segmentTable[middle];
|
|
|
|
|
|
|
|
if (logicalIp == s->logicalIp) {
|
|
|
|
return reinterpret_cast<intptr_t>(c->code.data + s->offset);
|
|
|
|
} else if (logicalIp < s->logicalIp) {
|
|
|
|
top = middle;
|
|
|
|
} else if (logicalIp > s->logicalIp) {
|
|
|
|
bottom = middle + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool resolved(Context* c) {
|
|
|
|
return c->codeLength >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
intptr_t logicalIp;
|
|
|
|
};
|
|
|
|
|
|
|
|
AddressOperand*
|
|
|
|
address(Context* c, MyPromise* p);
|
|
|
|
|
|
|
|
ImmediateOperand*
|
|
|
|
immediate(Context* c, int64_t v, SelectionType = DefaultSelection);
|
|
|
|
|
|
|
|
AbsoluteOperand*
|
|
|
|
absolute(Context* c, MyPromise* v);
|
|
|
|
|
|
|
|
RegisterOperand*
|
|
|
|
register_(Context* c, Register v, SelectionType = DefaultSelection);
|
|
|
|
|
2007-12-17 01:46:46 +00:00
|
|
|
RegisterOperand*
|
|
|
|
register_(Context* c, Register v, Register high,
|
|
|
|
SelectionType = DefaultSelection);
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
MemoryOperand*
|
|
|
|
memory(Context* c, MyOperand* base, int displacement,
|
|
|
|
MyOperand* index, unsigned scale, SelectionType = DefaultSelection);
|
|
|
|
|
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() { }
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual unsigned footprint(Context*) {
|
2007-12-09 20:03:21 +00:00
|
|
|
return BytesPerWord;
|
|
|
|
}
|
|
|
|
|
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-16 21:30:19 +00:00
|
|
|
virtual MyOperand* select(Context* c, SelectionType) { abort(c); }
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
virtual RegisterNode* dependencies(Context*, RegisterNode* next)
|
|
|
|
{ return next; }
|
|
|
|
|
2007-12-11 00:48:09 +00:00
|
|
|
virtual void release(Context*) { /* ignore */ }
|
2007-12-09 20:03:21 +00:00
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
virtual void setLabelValue(Context* c, MyPromise*) { abort(c); }
|
2007-12-09 20:03:21 +00:00
|
|
|
|
2007-12-14 18:27:56 +00:00
|
|
|
virtual void apply(Context*, Operation) = 0;
|
2007-12-09 20:03:21 +00:00
|
|
|
|
2007-12-14 18:27:56 +00:00
|
|
|
virtual void apply(Context*, Operation, MyOperand*) = 0;
|
2007-12-14 00:27:09 +00:00
|
|
|
|
2007-12-14 18:27:56 +00:00
|
|
|
virtual void accept(Context* c, Operation, RegisterOperand*) = 0;
|
2007-12-09 20:03:21 +00:00
|
|
|
|
2007-12-14 18:27:56 +00:00
|
|
|
virtual void accept(Context* c, Operation, ImmediateOperand*) = 0;
|
2007-12-11 23:52:28 +00:00
|
|
|
|
2007-12-14 18:27:56 +00:00
|
|
|
virtual void accept(Context* c, Operation, AbsoluteOperand*) = 0;
|
|
|
|
|
|
|
|
virtual void accept(Context* c, Operation, MemoryOperand*) = 0;
|
2007-12-16 21:30:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
acquire(Context* c, Register v)
|
|
|
|
{
|
|
|
|
assert(c, not c->registers[v].reserved);
|
|
|
|
if (Verbose) {
|
|
|
|
fprintf(stderr, "acquire %d\n", v);
|
|
|
|
}
|
|
|
|
c->registers[v].reserved = true;
|
|
|
|
}
|
2007-12-14 00:27:09 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
Register
|
|
|
|
acquire(Context* c)
|
|
|
|
{
|
|
|
|
// we don't yet support using r9-r15
|
|
|
|
for (int i = 8/*RegisterCount*/ - 1; i >= 0; --i) {
|
|
|
|
if (not c->registers[i].reserved) {
|
|
|
|
acquire(c, static_cast<Register>(i));
|
|
|
|
return static_cast<Register>(i);
|
|
|
|
}
|
|
|
|
}
|
2007-12-15 01:11:01 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
release(Context* c, Register v)
|
|
|
|
{
|
|
|
|
assert(c, c->registers[v].reserved);
|
|
|
|
if (Verbose) {
|
|
|
|
fprintf(stderr, "release %d\n", v);
|
|
|
|
}
|
|
|
|
c->registers[v].reserved = false;
|
|
|
|
}
|
2007-12-09 20:03:21 +00:00
|
|
|
|
|
|
|
class RegisterOperand: public MyOperand {
|
|
|
|
public:
|
2007-12-17 01:46:46 +00:00
|
|
|
RegisterOperand(Register value, Register high, SelectionType selection):
|
|
|
|
value(value), high(high), selection(selection)
|
2007-12-09 20:03:21 +00:00
|
|
|
{ }
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual unsigned footprint(Context*) {
|
|
|
|
return (selection == S8Selection ? 8 : BytesPerWord);
|
|
|
|
}
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
virtual Register asRegister(Context*) {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual MyOperand* select(Context* c, SelectionType selection) {
|
2007-12-17 01:46:46 +00:00
|
|
|
if (selection == this->selection) {
|
|
|
|
return this;
|
|
|
|
} else if (selection == S8Selection and BytesPerWord == 4) {
|
|
|
|
#warning tbc
|
|
|
|
return register_(c, value, acquire(c), selection);
|
|
|
|
} else {
|
|
|
|
return register_(c, value, selection);
|
|
|
|
}
|
2007-12-16 21:30:19 +00:00
|
|
|
}
|
2007-12-16 00:24:15 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual RegisterNode* dependencies(Context* c, RegisterNode* next) {
|
|
|
|
return new (c->zone.allocate(sizeof(RegisterNode)))
|
|
|
|
RegisterNode(value, next);
|
2007-12-14 00:27:09 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual void release(Context* c) {
|
|
|
|
::release(c, value);
|
2007-12-09 20:03:21 +00:00
|
|
|
}
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
virtual void apply(Context*, Operation);
|
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
|
|
|
}
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
virtual void accept(Context*, Operation, RegisterOperand*);
|
|
|
|
virtual void accept(Context*, Operation, ImmediateOperand*);
|
2007-12-11 23:52:28 +00:00
|
|
|
virtual void accept(Context*, Operation, AbsoluteOperand*);
|
2007-12-11 21:26:59 +00:00
|
|
|
virtual void accept(Context*, Operation, MemoryOperand*);
|
|
|
|
|
2007-12-09 20:03:21 +00:00
|
|
|
Register value;
|
2007-12-17 01:46:46 +00:00
|
|
|
Register high;
|
2007-12-16 21:30:19 +00:00
|
|
|
SelectionType selection;
|
2007-12-08 23:22:13 +00:00
|
|
|
};
|
|
|
|
|
2007-12-09 22:45:43 +00:00
|
|
|
class ImmediateOperand: public MyOperand {
|
|
|
|
public:
|
2007-12-16 21:30:19 +00:00
|
|
|
ImmediateOperand(int64_t value, SelectionType selection):
|
|
|
|
value(value), selection(selection)
|
2007-12-09 22:45:43 +00:00
|
|
|
{ }
|
2007-12-09 20:03:21 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual unsigned footprint(Context*) {
|
|
|
|
return (selection == S8Selection ? 8 : BytesPerWord);
|
|
|
|
}
|
2007-12-09 22:45:43 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual MyOperand* select(Context* c, SelectionType selection) {
|
|
|
|
return immediate(c, value, selection);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void apply(Context* c, Operation operation);
|
2007-12-14 18:27:56 +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
|
|
|
}
|
|
|
|
|
2007-12-14 18:27:56 +00:00
|
|
|
virtual void accept(Context* c, Operation, RegisterOperand*) { abort(c); }
|
|
|
|
virtual void accept(Context* c, Operation, ImmediateOperand*) { abort(c); }
|
|
|
|
virtual void accept(Context* c, Operation, AbsoluteOperand*) { abort(c); }
|
|
|
|
virtual void accept(Context* c, Operation, MemoryOperand*) { abort(c); }
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
int64_t value;
|
|
|
|
SelectionType selection;
|
2007-12-14 00:27:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class AddressOperand: public MyOperand {
|
|
|
|
public:
|
|
|
|
AddressOperand(MyPromise* promise):
|
|
|
|
promise(promise)
|
|
|
|
{ }
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
virtual Register asRegister(Context* c);
|
|
|
|
|
|
|
|
virtual void setLabelValue(Context*, MyPromise*);
|
2007-12-14 00:27:09 +00:00
|
|
|
|
|
|
|
virtual void apply(Context*, Operation);
|
2007-12-14 18:27:56 +00:00
|
|
|
virtual void apply(Context* c, Operation, MyOperand*) { abort(c); }
|
|
|
|
virtual void accept(Context* c, Operation, RegisterOperand*) { abort(c); }
|
|
|
|
virtual void accept(Context* c, Operation, ImmediateOperand*) { abort(c); }
|
|
|
|
virtual void accept(Context* c, Operation, AbsoluteOperand*) { abort(c); }
|
|
|
|
virtual void accept(Context* c, Operation, MemoryOperand*) { abort(c); }
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
MyPromise* promise;
|
2007-12-09 22:45:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class AbsoluteOperand: public MyOperand {
|
|
|
|
public:
|
2007-12-14 00:27:09 +00:00
|
|
|
AbsoluteOperand(MyPromise* promise):
|
|
|
|
promise(promise)
|
2007-12-09 22:45:43 +00:00
|
|
|
{ }
|
|
|
|
|
2007-12-15 01:11:01 +00:00
|
|
|
virtual Register asRegister(Context* c);
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
virtual void apply(Context*, Operation);
|
2007-12-11 21:26:59 +00:00
|
|
|
|
2007-12-11 23:52:28 +00:00
|
|
|
virtual void apply(Context* c, Operation operation, MyOperand* operand) {
|
|
|
|
operand->accept(c, operation, this);
|
|
|
|
}
|
|
|
|
|
2007-12-14 18:27:56 +00:00
|
|
|
virtual void accept(Context* c, Operation, RegisterOperand*) { abort(c); }
|
|
|
|
virtual void accept(Context* c, Operation, ImmediateOperand*) { abort(c); }
|
|
|
|
virtual void accept(Context* c, Operation, AbsoluteOperand*) { abort(c); }
|
|
|
|
virtual void accept(Context* c, Operation, MemoryOperand*) { abort(c); }
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
MyPromise* promise;
|
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,
|
2007-12-16 21:30:19 +00:00
|
|
|
unsigned scale, SelectionType selection):
|
2007-12-09 20:03:21 +00:00
|
|
|
base(base),
|
|
|
|
displacement(displacement),
|
|
|
|
index(index),
|
2007-12-16 21:30:19 +00:00
|
|
|
scale(scale),
|
|
|
|
selection(selection)
|
2007-12-14 00:27:09 +00:00
|
|
|
{ }
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual unsigned footprint(Context*) {
|
|
|
|
return (selection == S8Selection ? 8 : BytesPerWord);
|
2007-12-14 00:27:09 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual Register asRegister(Context*);
|
2007-12-14 00:27:09 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual MyOperand* select(Context* c, SelectionType selection) {
|
|
|
|
return memory(c, base, displacement, index, scale, selection);
|
|
|
|
}
|
2007-12-14 00:27:09 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual RegisterNode* dependencies(Context* c, RegisterNode* next) {
|
|
|
|
next = base->dependencies(c, next);
|
|
|
|
if (index) {
|
|
|
|
return index->dependencies(c, next);
|
|
|
|
} else {
|
|
|
|
return next;
|
2007-12-14 00:27:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual void apply(Context*, Operation);
|
|
|
|
|
|
|
|
virtual void apply(Context* c, Operation operation, MyOperand* operand) {
|
|
|
|
operand->accept(c, operation, this);
|
2007-12-14 00:27:09 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual void accept(Context*, Operation, RegisterOperand*);
|
|
|
|
virtual void accept(Context*, Operation, ImmediateOperand*);
|
|
|
|
virtual void accept(Context*, Operation, AbsoluteOperand*);
|
|
|
|
virtual void accept(Context*, Operation, MemoryOperand*);
|
|
|
|
|
|
|
|
MyOperand* base;
|
|
|
|
int displacement;
|
|
|
|
MyOperand* index;
|
|
|
|
unsigned scale;
|
|
|
|
SelectionType selection;
|
2007-12-14 00:27:09 +00:00
|
|
|
};
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
class WrapperOperand: public MyOperand {
|
2007-12-14 00:27:09 +00:00
|
|
|
public:
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual MyOperand* base(Context*) = 0;
|
2007-12-14 00:27:09 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual unsigned footprint(Context* c) {
|
|
|
|
return base(c)->footprint(c);
|
2007-12-14 00:27:09 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual Register asRegister(Context* c) {
|
|
|
|
return base(c)->asRegister(c);
|
2007-12-14 00:27:09 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual RegisterNode* dependencies(Context* c, RegisterNode* next) {
|
|
|
|
return base(c)->dependencies(c, next);
|
|
|
|
}
|
2007-12-14 00:27:09 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual void apply(Context* c, Operation operation) {
|
|
|
|
base(c)->apply(c, operation);
|
|
|
|
}
|
2007-12-14 00:27:09 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual void apply(Context* c, Operation operation, MyOperand* operand) {
|
|
|
|
base(c)->apply(c, operation, operand);
|
|
|
|
}
|
2007-12-14 00:27:09 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual void accept(Context* c, Operation operation,
|
|
|
|
RegisterOperand* operand)
|
|
|
|
{
|
|
|
|
base(c)->accept(c, operation, operand);
|
|
|
|
}
|
2007-12-14 00:27:09 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual void accept(Context* c, Operation operation,
|
|
|
|
ImmediateOperand* operand)
|
|
|
|
{
|
|
|
|
base(c)->accept(c, operation, operand);
|
2007-12-14 00:27:09 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual void accept(Context* c, Operation operation,
|
|
|
|
AbsoluteOperand* operand)
|
|
|
|
{
|
|
|
|
base(c)->accept(c, operation, operand);
|
2007-12-14 00:27:09 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual void accept(Context* c, Operation operation, MemoryOperand* operand)
|
|
|
|
{
|
|
|
|
base(c)->accept(c, operation, operand);
|
|
|
|
}
|
2007-12-14 00:27:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
AddressOperand*
|
|
|
|
address(Context* c, MyPromise* p)
|
2007-12-12 22:19:13 +00:00
|
|
|
{
|
2007-12-14 00:27:09 +00:00
|
|
|
return new (c->zone.allocate(sizeof(AddressOperand))) AddressOperand(p);
|
2007-12-12 22:19:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-09 20:03:21 +00:00
|
|
|
ImmediateOperand*
|
2007-12-17 01:46:46 +00:00
|
|
|
immediate(Context* c, int64_t v, SelectionType selection)
|
2007-12-09 20:03:21 +00:00
|
|
|
{
|
2007-12-16 21:30:19 +00:00
|
|
|
return new (c->zone.allocate(sizeof(ImmediateOperand)))
|
|
|
|
ImmediateOperand(v, selection);
|
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*
|
2007-12-16 21:30:19 +00:00
|
|
|
register_(Context* c, Register v, SelectionType selection)
|
2007-12-09 20:03:21 +00:00
|
|
|
{
|
2007-12-17 01:46:46 +00:00
|
|
|
assert(c, BytesPerWord != 4 or selection != S8Selection);
|
2007-12-16 21:30:19 +00:00
|
|
|
return new (c->zone.allocate(sizeof(RegisterOperand)))
|
|
|
|
RegisterOperand(v, selection);
|
2007-12-09 20:03:21 +00:00
|
|
|
}
|
|
|
|
|
2007-12-17 01:46:46 +00:00
|
|
|
RegisterOperand*
|
|
|
|
register_(Context* c, Register v, Register high, SelectionType selection)
|
|
|
|
{
|
|
|
|
return new (c->zone.allocate(sizeof(RegisterOperand)))
|
|
|
|
RegisterOperand(v, high, selection);
|
|
|
|
}
|
|
|
|
|
2007-12-09 20:03:21 +00:00
|
|
|
MemoryOperand*
|
|
|
|
memory(Context* c, MyOperand* base, int displacement,
|
2007-12-16 21:30:19 +00:00
|
|
|
MyOperand* index, unsigned scale, SelectionType selection)
|
2007-12-09 20:03:21 +00:00
|
|
|
{
|
2007-12-11 00:48:09 +00:00
|
|
|
return new (c->zone.allocate(sizeof(MemoryOperand)))
|
2007-12-16 21:30:19 +00:00
|
|
|
MemoryOperand(base, displacement, index, scale, selection);
|
2007-12-09 20:03:21 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
RegisterOperand*
|
|
|
|
temporary(Context* c)
|
2007-12-11 21:26:59 +00:00
|
|
|
{
|
2007-12-16 21:30:19 +00:00
|
|
|
return register_(c, acquire(c));
|
2007-12-11 21:26:59 +00:00
|
|
|
}
|
|
|
|
|
2007-12-11 00:48:09 +00:00
|
|
|
RegisterOperand*
|
2007-12-16 21:30:19 +00:00
|
|
|
temporary(Context* c, Register v)
|
2007-12-11 00:48:09 +00:00
|
|
|
{
|
2007-12-16 21:30:19 +00:00
|
|
|
acquire(c, v);
|
|
|
|
return register_(c, v);
|
2007-12-11 00:48:09 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
Segment*
|
|
|
|
currentSegment(Context* c)
|
2007-12-14 18:27:56 +00:00
|
|
|
{
|
2007-12-16 21:30:19 +00:00
|
|
|
Segment* s; c->plan.get(c->plan.length() - BytesPerWord, &s, BytesPerWord);
|
|
|
|
return s;
|
2007-12-14 18:27:56 +00:00
|
|
|
}
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
void
|
|
|
|
apply(Context* c, MyOperand::Operation op)
|
|
|
|
{
|
|
|
|
switch (op) {
|
|
|
|
case MyOperand::ret:
|
|
|
|
c->code.append(0xc3);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
class RegisterReference {
|
|
|
|
public:
|
|
|
|
RegisterReference(): valid(false) { }
|
|
|
|
|
|
|
|
Register value(Context* c) {
|
|
|
|
assert(c, valid);
|
|
|
|
return value_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void acquire(Context* c) {
|
|
|
|
value_ = ::acquire(c);
|
|
|
|
valid = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void release(Context* c) {
|
|
|
|
::release(c, value_);
|
|
|
|
valid = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Register value_;
|
|
|
|
bool valid;
|
|
|
|
};
|
|
|
|
|
|
|
|
class TemporaryOperand: public WrapperOperand {
|
|
|
|
public:
|
|
|
|
TemporaryOperand(RegisterReference* reference, SelectionType selection):
|
|
|
|
reference(reference), selection(selection)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual MyOperand* base(Context* c) {
|
|
|
|
return register_(c, reference->value(c), selection);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual unsigned footprint(Context*) {
|
|
|
|
return (selection == S8Selection ? 8 : BytesPerWord);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual MyOperand* select(Context* c, SelectionType selection) {
|
|
|
|
return new (c->zone.allocate(sizeof(TemporaryOperand)))
|
|
|
|
TemporaryOperand(reference, selection);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void release(Context* c) {
|
|
|
|
reference->release(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
RegisterReference* reference;
|
|
|
|
SelectionType selection;
|
|
|
|
};
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
class OpEvent: public Event {
|
|
|
|
public:
|
|
|
|
OpEvent(MyOperand::Operation operation, Event* next):
|
|
|
|
Event(next), operation(operation)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual void run(Context* c) {
|
|
|
|
apply(c, operation);
|
|
|
|
}
|
|
|
|
|
|
|
|
MyOperand::Operation operation;
|
|
|
|
};
|
|
|
|
|
|
|
|
class UnaryOpEvent: public Event {
|
|
|
|
public:
|
|
|
|
UnaryOpEvent(MyOperand::Operation operation, Operand* operand, Event* next):
|
|
|
|
Event(next),
|
|
|
|
operation(operation),
|
|
|
|
operand(static_cast<MyOperand*>(operand))
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual void run(Context* c) {
|
2007-12-16 21:30:19 +00:00
|
|
|
if (Verbose) {
|
2007-12-14 18:27:56 +00:00
|
|
|
fprintf(stderr, "unary %d\n", operation);
|
|
|
|
}
|
2007-12-14 00:27:09 +00:00
|
|
|
operand->apply(c, operation);
|
|
|
|
}
|
|
|
|
|
|
|
|
MyOperand::Operation operation;
|
|
|
|
MyOperand* operand;
|
|
|
|
};
|
|
|
|
|
|
|
|
class BinaryOpEvent: public Event {
|
|
|
|
public:
|
|
|
|
BinaryOpEvent(MyOperand::Operation operation, Operand* a, Operand* b,
|
|
|
|
Event* next):
|
|
|
|
Event(next),
|
|
|
|
operation(operation),
|
|
|
|
a(static_cast<MyOperand*>(a)),
|
|
|
|
b(static_cast<MyOperand*>(b))
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual void run(Context* c) {
|
2007-12-16 21:30:19 +00:00
|
|
|
if (Verbose) {
|
2007-12-14 18:27:56 +00:00
|
|
|
fprintf(stderr, "binary %d\n", operation);
|
|
|
|
}
|
2007-12-14 00:27:09 +00:00
|
|
|
a->apply(c, operation, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
MyOperand::Operation operation;
|
|
|
|
MyOperand* a;
|
|
|
|
MyOperand* b;
|
|
|
|
};
|
|
|
|
|
|
|
|
class AcquireEvent: public Event {
|
|
|
|
public:
|
|
|
|
AcquireEvent(TemporaryOperand* operand, Event* next):
|
|
|
|
Event(next),
|
|
|
|
operand(operand)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual void run(Context* c) {
|
2007-12-16 21:30:19 +00:00
|
|
|
operand->reference->acquire(c);
|
2007-12-14 00:27:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TemporaryOperand* operand;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ReleaseEvent: public Event {
|
|
|
|
public:
|
|
|
|
ReleaseEvent(Operand* operand, Event* next):
|
|
|
|
Event(next),
|
|
|
|
operand(static_cast<MyOperand*>(operand))
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual void run(Context* c) {
|
|
|
|
operand->release(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
MyOperand* operand;
|
|
|
|
};
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
|
|
|
|
class Movement {
|
|
|
|
public:
|
|
|
|
MyOperand* source;
|
|
|
|
Register destination;
|
|
|
|
RegisterNode* dependencies;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
push(Context* c, Movement* table, unsigned size)
|
|
|
|
{
|
|
|
|
int pushed[size];
|
|
|
|
unsigned pushIndex = 0;
|
|
|
|
for (unsigned i = 0; i < size; ++i) {
|
|
|
|
Movement* mi = table + i;
|
|
|
|
for (unsigned j = i + 1; j < size; ++j) {
|
|
|
|
Movement* mj = table + j;
|
|
|
|
for (RegisterNode* d = mj->dependencies; d; d = d->next) {
|
|
|
|
if (mi->destination == d->value) {
|
|
|
|
mi->source->apply(c, MyOperand::push);
|
|
|
|
pushed[pushIndex++] = i;
|
|
|
|
goto loop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mi->source->apply(c, MyOperand::mov, register_(c, mi->destination));
|
|
|
|
loop:;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = pushIndex - 1; i >= 0; --i) {
|
|
|
|
register_(c, table[pushed[i]].destination)->apply
|
|
|
|
(c, MyOperand::pop);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class ArgumentEvent: public Event {
|
|
|
|
public:
|
|
|
|
ArgumentEvent(MyOperand** arguments, unsigned count, Event* next):
|
|
|
|
Event(next),
|
|
|
|
arguments(arguments),
|
|
|
|
count(count)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual void run(Context* c) {
|
|
|
|
if (BytesPerWord == 8) {
|
|
|
|
const unsigned size = min(count, GprParameterCount);
|
|
|
|
Movement moveTable[size];
|
|
|
|
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
if (static_cast<unsigned>(i) < GprParameterCount) {
|
|
|
|
Movement* m = moveTable + (size - i - 1);
|
|
|
|
m->source = arguments[i];
|
|
|
|
m->destination = gpRegister(c, i);
|
|
|
|
m->dependencies = arguments[i]->dependencies(c, 0);
|
|
|
|
} else {
|
|
|
|
arguments[i]->apply(c, MyOperand::push);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
push(c, moveTable, size);
|
|
|
|
} else {
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
arguments[i]->apply(c, MyOperand::push);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MyOperand** arguments;
|
|
|
|
unsigned count;
|
|
|
|
};
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
void
|
|
|
|
appendOperation(Context* c, MyOperand::Operation operation)
|
|
|
|
{
|
|
|
|
Segment* s = currentSegment(c);
|
|
|
|
s->event = new (c->zone.allocate(sizeof(OpEvent)))
|
|
|
|
OpEvent(operation, s->event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
appendOperation(Context* c, MyOperand::Operation operation, Operand* operand)
|
|
|
|
{
|
|
|
|
Segment* s = currentSegment(c);
|
|
|
|
s->event = new (c->zone.allocate(sizeof(UnaryOpEvent)))
|
|
|
|
UnaryOpEvent(operation, operand, s->event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
appendOperation(Context* c, MyOperand::Operation operation, Operand* a, Operand* b)
|
|
|
|
{
|
|
|
|
Segment* s = currentSegment(c);
|
|
|
|
s->event = new (c->zone.allocate(sizeof(BinaryOpEvent)))
|
|
|
|
BinaryOpEvent(operation, a, b, s->event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
appendAcquire(Context* c, TemporaryOperand* operand)
|
|
|
|
{
|
|
|
|
Segment* s = currentSegment(c);
|
|
|
|
s->event = new (c->zone.allocate(sizeof(AcquireEvent)))
|
|
|
|
AcquireEvent(operand, s->event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
appendRelease(Context* c, Operand* operand)
|
|
|
|
{
|
|
|
|
Segment* s = currentSegment(c);
|
|
|
|
s->event = new (c->zone.allocate(sizeof(ReleaseEvent)))
|
|
|
|
ReleaseEvent(operand, s->event);
|
|
|
|
}
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
void
|
|
|
|
appendArgumentEvent(Context* c, MyOperand** arguments, unsigned count)
|
|
|
|
{
|
|
|
|
Segment* s = currentSegment(c);
|
|
|
|
s->event = new (c->zone.allocate(sizeof(ArgumentEvent)))
|
|
|
|
ArgumentEvent(arguments, count, s->event);
|
|
|
|
}
|
|
|
|
|
|
|
|
MyStack*
|
2007-12-17 01:46:46 +00:00
|
|
|
pushed(Context* c, MyStack* stack, unsigned footprint)
|
2007-12-11 00:48:09 +00:00
|
|
|
{
|
2007-12-16 00:24:15 +00:00
|
|
|
int index = (stack ?
|
2007-12-16 21:30:19 +00:00
|
|
|
stack->index + (stack->value->footprint(c) / BytesPerWord) :
|
2007-12-12 18:59:45 +00:00
|
|
|
0);
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
MyOperand* value = memory
|
2007-12-17 01:46:46 +00:00
|
|
|
(c, register_(c, rbp), - (c->reserved + index + 1) * BytesPerWord, 0, 1,
|
|
|
|
footprint == (BytesPerWord * 2) ? S8Selection : DefaultSelection);
|
2007-12-12 18:59:45 +00:00
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
return new (c->zone.allocate(sizeof(MyStack))) MyStack(value, index, stack);
|
2007-12-11 00:48:09 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
MyStack*
|
|
|
|
push(Context* c, MyStack* stack, int count)
|
2007-12-12 22:19:13 +00:00
|
|
|
{
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation
|
|
|
|
(c, MyOperand::sub, immediate(c, count * BytesPerWord), register_(c, rsp));
|
2007-12-13 00:18:31 +00:00
|
|
|
|
2007-12-12 22:19:13 +00:00
|
|
|
while (count) {
|
|
|
|
-- count;
|
2007-12-17 01:46:46 +00:00
|
|
|
stack = pushed(c, stack, BytesPerWord);
|
2007-12-12 22:19:13 +00:00
|
|
|
}
|
2007-12-16 00:24:15 +00:00
|
|
|
|
|
|
|
return stack;
|
2007-12-12 22:19:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
MyStack*
|
|
|
|
push(Context* c, MyStack* stack, MyOperand* v)
|
2007-12-12 22:19:13 +00:00
|
|
|
{
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(c, MyOperand::push, v);
|
|
|
|
|
2007-12-17 01:46:46 +00:00
|
|
|
return pushed(c, stack, v->footprint(c));
|
2007-12-12 22:19:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
MyStack*
|
|
|
|
pop(Context* c, MyStack* stack, int count)
|
2007-12-12 22:19:13 +00:00
|
|
|
{
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation
|
|
|
|
(c, MyOperand::add, immediate(c, count * BytesPerWord), register_(c, rsp));
|
2007-12-13 00:18:31 +00:00
|
|
|
|
2007-12-12 22:19:13 +00:00
|
|
|
while (count) {
|
2007-12-16 21:30:19 +00:00
|
|
|
count -= (stack->value->footprint(c) / BytesPerWord);
|
2007-12-12 22:19:13 +00:00
|
|
|
assert(c, count >= 0);
|
2007-12-16 00:24:15 +00:00
|
|
|
stack = stack->next;
|
2007-12-12 22:19:13 +00:00
|
|
|
}
|
2007-12-16 00:24:15 +00:00
|
|
|
|
|
|
|
return stack;
|
2007-12-12 22:19:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
MyStack*
|
|
|
|
pop(Context* c, MyStack* stack, MyOperand* dst)
|
2007-12-11 00:48:09 +00:00
|
|
|
{
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(c, MyOperand::pop, dst);
|
2007-12-11 00:48:09 +00:00
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
return stack->next;
|
2007-12-09 22:45:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
pushArguments(Context* c, unsigned count, va_list list)
|
|
|
|
{
|
2007-12-16 00:24:15 +00:00
|
|
|
MyOperand** arguments = static_cast<MyOperand**>
|
|
|
|
(c->zone.allocate(count * BytesPerWord));
|
2007-12-09 22:45:43 +00:00
|
|
|
unsigned footprint = 0;
|
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
|
|
|
arguments[i] = va_arg(list, MyOperand*);
|
2007-12-16 21:30:19 +00:00
|
|
|
footprint += pad(arguments[i]->footprint(c));
|
2007-12-09 22:45:43 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
appendArgumentEvent(c, arguments, count);
|
2007-12-09 22:45:43 +00:00
|
|
|
|
2007-12-09 23:06:47 +00:00
|
|
|
if (BytesPerWord == 8) {
|
2007-12-16 00:24:15 +00:00
|
|
|
if (footprint > GprParameterCount * BytesPerWord) {
|
|
|
|
return footprint - GprParameterCount * BytesPerWord;
|
2007-12-09 23:06:47 +00:00
|
|
|
} 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
|
2007-12-14 01:59:56 +00:00
|
|
|
encode(Context* c, uint8_t instruction, int a, Register b,
|
|
|
|
int32_t displacement, int index, unsigned scale)
|
2007-12-11 00:48:09 +00:00
|
|
|
{
|
|
|
|
c->code.append(instruction);
|
|
|
|
|
2007-12-14 01:59:56 +00:00
|
|
|
uint8_t width;
|
|
|
|
if (displacement == 0 and b != rbp) {
|
|
|
|
width = 0;
|
|
|
|
} else if (isInt8(displacement)) {
|
|
|
|
width = 0x40;
|
2007-12-11 00:48:09 +00:00
|
|
|
} else {
|
2007-12-14 01:59:56 +00:00
|
|
|
width = 0x80;
|
2007-12-11 00:48:09 +00:00
|
|
|
}
|
|
|
|
|
2007-12-14 01:59:56 +00:00
|
|
|
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);
|
2007-12-11 00:48:09 +00:00
|
|
|
}
|
|
|
|
|
2007-12-14 01:59:56 +00:00
|
|
|
if (displacement == 0 and b != rbp) {
|
2007-12-11 00:48:09 +00:00
|
|
|
// do nothing
|
2007-12-14 01:59:56 +00:00
|
|
|
} else if (isInt8(displacement)) {
|
|
|
|
c->code.append(displacement);
|
2007-12-11 00:48:09 +00:00
|
|
|
} else {
|
2007-12-14 01:59:56 +00:00
|
|
|
c->code.append4(displacement);
|
2007-12-11 00:48:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-14 01:59:56 +00:00
|
|
|
void
|
|
|
|
encode(Context* c, uint8_t instruction, int a, MemoryOperand* b, bool rex)
|
|
|
|
{
|
|
|
|
Register r = b->base->asRegister(c);
|
|
|
|
int index = b->index ? b->index->asRegister(c) : -1;
|
|
|
|
if (rex) {
|
|
|
|
::rex(c);
|
|
|
|
}
|
|
|
|
encode(c, instruction, a, r, b->displacement, index, b->scale);
|
|
|
|
}
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
void
|
|
|
|
RegisterOperand::apply(Context* c, Operation operation)
|
|
|
|
{
|
2007-12-16 21:30:19 +00:00
|
|
|
assert(c, selection == DefaultSelection);
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
switch (operation) {
|
2007-12-12 01:19:03 +00:00
|
|
|
case call:
|
|
|
|
c->code.append(0xff);
|
|
|
|
c->code.append(0xd0 | value);
|
2007-12-11 21:26:59 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case jmp:
|
|
|
|
c->code.append(0xff);
|
|
|
|
c->code.append(0xe0 | value);
|
|
|
|
break;
|
|
|
|
|
2007-12-12 01:19:03 +00:00
|
|
|
case pop:
|
|
|
|
c->code.append(0x58 | value);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case push:
|
|
|
|
c->code.append(0x50 | value);
|
2007-12-11 21:26:59 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default: abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
RegisterOperand::accept(Context* c, Operation operation,
|
|
|
|
RegisterOperand* operand)
|
|
|
|
{
|
2007-12-16 21:30:19 +00:00
|
|
|
assert(c, selection == DefaultSelection);
|
|
|
|
assert(c, operation == mov or operand->selection == DefaultSelection);
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
switch (operation) {
|
2007-12-12 01:19:03 +00:00
|
|
|
case add:
|
|
|
|
rex(c);
|
|
|
|
c->code.append(0x01);
|
|
|
|
c->code.append(0xc0 | (operand->value << 3) | value);
|
|
|
|
break;
|
|
|
|
|
2007-12-12 22:19:13 +00:00
|
|
|
case cmp:
|
|
|
|
rex(c);
|
|
|
|
c->code.append(0x39);
|
|
|
|
c->code.append(0xc0 | (operand->value << 3) | value);
|
|
|
|
break;
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
case mov:
|
2007-12-16 21:30:19 +00:00
|
|
|
if (value != operand->value or selection != operand->selection) {
|
|
|
|
if (operand->selection == DefaultSelection) {
|
|
|
|
rex(c);
|
|
|
|
c->code.append(0x89);
|
|
|
|
c->code.append(0xc0 | (operand->value << 3) | value);
|
|
|
|
} else {
|
|
|
|
switch (operand->selection) {
|
|
|
|
case S1Selection:
|
|
|
|
c->code.append(0xbe);
|
|
|
|
break;
|
2007-12-11 21:26:59 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
case S2Selection:
|
|
|
|
c->code.append(0xbf);
|
|
|
|
break;
|
2007-12-15 01:11:01 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
case Z2Selection:
|
|
|
|
c->code.append(0xb7);
|
|
|
|
break;
|
2007-12-15 01:11:01 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
case S4Selection:
|
|
|
|
c->code.append(0x89);
|
|
|
|
break;
|
2007-12-15 01:11:01 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
default: abort(c);
|
|
|
|
}
|
2007-12-15 01:11:01 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
c->code.append(0xc0 | (operand->value << 3) | value);
|
|
|
|
}
|
2007-12-15 01:11:01 +00:00
|
|
|
}
|
2007-12-16 21:30:19 +00:00
|
|
|
break;
|
2007-12-15 01:11:01 +00:00
|
|
|
|
2007-12-16 23:52:38 +00:00
|
|
|
case mul:
|
|
|
|
rex(c);
|
|
|
|
c->code.append(0x0f);
|
|
|
|
c->code.append(0xaf);
|
|
|
|
c->code.append(0xc0 | (value << 3) | operand->value);
|
|
|
|
break;
|
|
|
|
|
2007-12-15 01:11:01 +00:00
|
|
|
default: abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
void
|
|
|
|
RegisterOperand::accept(Context* c, Operation operation,
|
|
|
|
ImmediateOperand* operand)
|
|
|
|
{
|
2007-12-16 21:30:19 +00:00
|
|
|
assert(c, selection == DefaultSelection);
|
|
|
|
assert(c, operand->selection == DefaultSelection);
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
switch (operation) {
|
2007-12-12 22:19:13 +00:00
|
|
|
case add: {
|
2007-12-14 00:27:09 +00:00
|
|
|
if (operand->value) {
|
|
|
|
assert(c, isInt8(operand->value)); // todo
|
2007-12-12 18:59:45 +00:00
|
|
|
|
|
|
|
rex(c);
|
|
|
|
c->code.append(0x83);
|
|
|
|
c->code.append(0xc0 | value);
|
2007-12-14 00:27:09 +00:00
|
|
|
c->code.append(operand->value);
|
2007-12-12 18:59:45 +00:00
|
|
|
}
|
2007-12-12 22:19:13 +00:00
|
|
|
} break;
|
2007-12-12 18:59:45 +00:00
|
|
|
|
2007-12-12 22:19:13 +00:00
|
|
|
case and_: {
|
2007-12-16 00:24:15 +00:00
|
|
|
rex(c);
|
|
|
|
if (isInt8(operand->value)) {
|
|
|
|
c->code.append(0x83);
|
|
|
|
c->code.append(0xe0 | value);
|
|
|
|
c->code.append(operand->value);
|
|
|
|
} else {
|
|
|
|
assert(c, isInt32(operand->value));
|
2007-12-12 01:19:03 +00:00
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
c->code.append(0x81);
|
|
|
|
c->code.append(0xe0 | value);
|
|
|
|
c->code.append(operand->value);
|
2007-12-12 01:19:03 +00:00
|
|
|
}
|
2007-12-12 22:19:13 +00:00
|
|
|
} break;
|
2007-12-12 01:19:03 +00:00
|
|
|
|
2007-12-12 22:19:13 +00:00
|
|
|
case cmp: {
|
2007-12-14 00:27:09 +00:00
|
|
|
assert(c, isInt8(operand->value)); // todo
|
2007-12-12 22:19:13 +00:00
|
|
|
|
2007-12-13 00:18:31 +00:00
|
|
|
rex(c);
|
|
|
|
c->code.append(0x83);
|
|
|
|
c->code.append(0xf8 | value);
|
2007-12-14 00:27:09 +00:00
|
|
|
c->code.append(operand->value);
|
2007-12-12 22:19:13 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case mov: {
|
2007-12-11 23:52:28 +00:00
|
|
|
rex(c);
|
|
|
|
c->code.append(0xb8 | value);
|
2007-12-14 00:27:09 +00:00
|
|
|
c->code.appendAddress(operand->value);
|
2007-12-12 22:19:13 +00:00
|
|
|
} break;
|
2007-12-11 23:52:28 +00:00
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
case shl: {
|
|
|
|
if (operand->value) {
|
|
|
|
rex(c);
|
|
|
|
if (operand->value == 1) {
|
|
|
|
c->code.append(0xd1);
|
|
|
|
c->code.append(0xe0 | value);
|
|
|
|
} else {
|
|
|
|
assert(c, isInt8(operand->value));
|
|
|
|
|
|
|
|
c->code.append(0xc1);
|
|
|
|
c->code.append(0xe0 | value);
|
|
|
|
c->code.append(operand->value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
2007-12-12 22:19:13 +00:00
|
|
|
case sub: {
|
2007-12-14 00:27:09 +00:00
|
|
|
if (operand->value) {
|
|
|
|
assert(c, isInt8(operand->value)); // todo
|
2007-12-11 21:26:59 +00:00
|
|
|
|
2007-12-11 23:52:28 +00:00
|
|
|
rex(c);
|
|
|
|
c->code.append(0x83);
|
|
|
|
c->code.append(0xe8 | value);
|
2007-12-14 00:27:09 +00:00
|
|
|
c->code.append(operand->value);
|
2007-12-11 23:52:28 +00:00
|
|
|
}
|
2007-12-12 22:19:13 +00:00
|
|
|
} break;
|
2007-12-11 21:26:59 +00:00
|
|
|
|
|
|
|
default: abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
RegisterOperand::accept(Context* c, Operation operation,
|
|
|
|
MemoryOperand* operand)
|
|
|
|
{
|
2007-12-16 21:30:19 +00:00
|
|
|
assert(c, selection == DefaultSelection);
|
|
|
|
assert(c, operation == mov or operand->selection == DefaultSelection);
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
switch (operation) {
|
2007-12-14 00:27:09 +00:00
|
|
|
case cmp: {
|
2007-12-14 01:59:56 +00:00
|
|
|
encode(c, 0x3b, value, operand, true);
|
2007-12-14 00:27:09 +00:00
|
|
|
} break;
|
2007-12-13 00:18:31 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
case mov: {
|
2007-12-16 21:30:19 +00:00
|
|
|
if (operand->selection == DefaultSelection) {
|
|
|
|
encode(c, 0x8b, value, operand, true);
|
|
|
|
} else {
|
|
|
|
switch (operand->selection) {
|
|
|
|
case S1Selection:
|
|
|
|
rex(c);
|
|
|
|
c->code.append(0x0f);
|
|
|
|
encode(c, 0xbe, value, operand, false);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case S2Selection:
|
|
|
|
rex(c);
|
|
|
|
c->code.append(0x0f);
|
|
|
|
encode(c, 0xbf, value, operand, false);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Z2Selection:
|
|
|
|
rex(c);
|
|
|
|
c->code.append(0x0f);
|
|
|
|
encode(c, 0xb7, value, operand, false);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case S4Selection:
|
|
|
|
encode(c, 0x63, value, operand, true);
|
|
|
|
break;
|
|
|
|
|
2007-12-17 01:46:46 +00:00
|
|
|
case S8Selection:
|
|
|
|
assert(c, selection == S8Selection);
|
|
|
|
|
|
|
|
register_(c, value)->accept
|
|
|
|
(c, mov, memory
|
|
|
|
(c, operand->base, operand->displacement,
|
|
|
|
operand->index, operand->scale));
|
|
|
|
|
|
|
|
register_(c, high)->accept
|
|
|
|
(c, mov, memory
|
|
|
|
(c, operand->base, operand->displacement + BytesPerWord,
|
|
|
|
operand->index, operand->scale));
|
|
|
|
break;
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
default: abort(c);
|
|
|
|
}
|
2007-12-14 00:27:09 +00:00
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default: abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ImmediateOperand*
|
|
|
|
value(Context* c, AbsoluteOperand* operand)
|
2007-12-12 18:59:45 +00:00
|
|
|
{
|
2007-12-16 21:30:19 +00:00
|
|
|
if (operand->promise->resolved(c)) {
|
2007-12-16 00:24:15 +00:00
|
|
|
return immediate(c, operand->promise->value(c));
|
2007-12-14 00:27:09 +00:00
|
|
|
} else {
|
|
|
|
return immediate(c, 0);
|
|
|
|
}
|
2007-12-12 18:59:45 +00:00
|
|
|
}
|
|
|
|
|
2007-12-11 23:52:28 +00:00
|
|
|
void
|
|
|
|
RegisterOperand::accept(Context* c, Operation operation,
|
|
|
|
AbsoluteOperand* operand)
|
|
|
|
{
|
|
|
|
switch (operation) {
|
2007-12-13 00:18:31 +00:00
|
|
|
case cmp: {
|
|
|
|
RegisterOperand* tmp = temporary(c);
|
2007-12-14 00:27:09 +00:00
|
|
|
tmp->accept(c, mov, ::value(c, operand));
|
2007-12-13 00:18:31 +00:00
|
|
|
accept(c, cmp, memory(c, tmp, 0, 0, 1));
|
|
|
|
tmp->release(c);
|
|
|
|
} break;
|
|
|
|
|
2007-12-11 23:52:28 +00:00
|
|
|
case mov: {
|
2007-12-14 00:27:09 +00:00
|
|
|
accept(c, mov, ::value(c, operand));
|
2007-12-11 23:52:28 +00:00
|
|
|
accept(c, mov, memory(c, this, 0, 0, 1));
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default: abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-12 18:59:45 +00:00
|
|
|
void
|
2007-12-14 00:27:09 +00:00
|
|
|
unconditional(Context* c, unsigned jump, AddressOperand* operand)
|
2007-12-11 21:26:59 +00:00
|
|
|
{
|
2007-12-14 00:27:09 +00:00
|
|
|
intptr_t v;
|
2007-12-16 21:30:19 +00:00
|
|
|
if (operand->promise->resolved(c)) {
|
2007-12-14 00:27:09 +00:00
|
|
|
uint8_t* instruction = c->code.data + c->code.length();
|
|
|
|
v = reinterpret_cast<uint8_t*>(operand->promise->value(c))
|
|
|
|
- instruction - 5;
|
|
|
|
} else {
|
|
|
|
v = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
c->code.append(jump);
|
|
|
|
c->code.append4(v);
|
2007-12-12 22:19:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-12-14 00:27:09 +00:00
|
|
|
conditional(Context* c, unsigned condition, AddressOperand* operand)
|
2007-12-12 22:19:13 +00:00
|
|
|
{
|
2007-12-14 00:27:09 +00:00
|
|
|
intptr_t v;
|
2007-12-16 21:30:19 +00:00
|
|
|
if (operand->promise->resolved(c)) {
|
2007-12-14 00:27:09 +00:00
|
|
|
uint8_t* instruction = c->code.data + c->code.length();
|
|
|
|
v = reinterpret_cast<uint8_t*>(operand->promise->value(c))
|
|
|
|
- instruction - 6;
|
|
|
|
} else {
|
|
|
|
v = 0;
|
|
|
|
}
|
2007-12-12 22:19:13 +00:00
|
|
|
|
|
|
|
c->code.append(0x0f);
|
|
|
|
c->code.append(condition);
|
2007-12-14 00:27:09 +00:00
|
|
|
c->code.append4(v);
|
2007-12-11 21:26:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-12-16 00:24:15 +00:00
|
|
|
AddressOperand::setLabelValue(Context*, MyPromise* p)
|
2007-12-14 00:27:09 +00:00
|
|
|
{
|
|
|
|
promise = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
AddressOperand::apply(Context* c, Operation operation)
|
2007-12-11 21:26:59 +00:00
|
|
|
{
|
|
|
|
switch (operation) {
|
2007-12-12 01:19:03 +00:00
|
|
|
case alignedCall: {
|
|
|
|
while ((c->code.length() + 1) % 4) {
|
|
|
|
c->code.append(0x90);
|
|
|
|
}
|
|
|
|
apply(c, call);
|
|
|
|
} break;
|
|
|
|
|
2007-12-12 22:19:13 +00:00
|
|
|
case call:
|
2007-12-14 00:27:09 +00:00
|
|
|
unconditional(c, 0xe8, this);
|
2007-12-12 22:19:13 +00:00
|
|
|
break;
|
2007-12-12 18:59:45 +00:00
|
|
|
|
2007-12-12 22:19:13 +00:00
|
|
|
case jmp:
|
2007-12-14 00:27:09 +00:00
|
|
|
unconditional(c, 0xe9, this);
|
2007-12-12 22:19:13 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case je:
|
2007-12-14 00:27:09 +00:00
|
|
|
conditional(c, 0x84, this);
|
2007-12-12 22:19:13 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case jne:
|
2007-12-14 00:27:09 +00:00
|
|
|
conditional(c, 0x85, this);
|
2007-12-12 22:19:13 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case jg:
|
2007-12-14 00:27:09 +00:00
|
|
|
conditional(c, 0x8f, this);
|
2007-12-12 22:19:13 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case jge:
|
2007-12-14 00:27:09 +00:00
|
|
|
conditional(c, 0x8d, this);
|
2007-12-12 22:19:13 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case jl:
|
2007-12-14 00:27:09 +00:00
|
|
|
conditional(c, 0x8c, this);
|
2007-12-12 22:19:13 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case jle:
|
2007-12-14 00:27:09 +00:00
|
|
|
conditional(c, 0x8e, this);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
Register
|
|
|
|
AddressOperand::asRegister(Context* c)
|
|
|
|
{
|
|
|
|
intptr_t v;
|
|
|
|
if (c->codeLength >= 0) {
|
|
|
|
v = promise->value(c);
|
|
|
|
} else {
|
|
|
|
v = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
RegisterOperand* tmp = temporary(c);
|
|
|
|
tmp->accept(c, mov, immediate(c, v));
|
|
|
|
tmp->release(c);
|
|
|
|
return tmp->value;
|
|
|
|
}
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
void
|
|
|
|
ImmediateOperand::apply(Context* c, Operation operation)
|
|
|
|
{
|
2007-12-17 01:46:46 +00:00
|
|
|
assert(c, operation == push or selection == DefaultSelection);
|
2007-12-16 21:30:19 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
switch (operation) {
|
|
|
|
case alignedCall:
|
|
|
|
case call:
|
|
|
|
case jmp:
|
|
|
|
address(c, new (c->zone.allocate(sizeof(ResolvedPromise)))
|
|
|
|
ResolvedPromise(value))->apply(c, operation);
|
2007-12-12 22:19:13 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case push: {
|
2007-12-17 01:46:46 +00:00
|
|
|
if (selection == DefaultSelection) {
|
|
|
|
if (isInt8(value)) {
|
|
|
|
c->code.append(0x6a);
|
|
|
|
c->code.append(value);
|
|
|
|
} else if (isInt32(value)) {
|
|
|
|
c->code.append(0x68);
|
|
|
|
c->code.append4(value);
|
|
|
|
} else {
|
|
|
|
RegisterOperand* tmp = temporary(c);
|
|
|
|
tmp->accept(c, mov, this);
|
|
|
|
tmp->apply(c, push);
|
|
|
|
tmp->release(c);
|
|
|
|
}
|
2007-12-12 18:59:45 +00:00
|
|
|
} else {
|
2007-12-17 01:46:46 +00:00
|
|
|
immediate(c, (value >> 32) & 0xFFFFFFFF)->apply(c, push);
|
|
|
|
immediate(c, (value ) & 0xFFFFFFFF)->apply(c, push);
|
2007-12-12 18:59:45 +00:00
|
|
|
}
|
2007-12-12 22:19:13 +00:00
|
|
|
} break;
|
2007-12-11 21:26:59 +00:00
|
|
|
|
|
|
|
default: abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-15 01:11:01 +00:00
|
|
|
Register
|
|
|
|
AbsoluteOperand::asRegister(Context* c)
|
|
|
|
{
|
|
|
|
RegisterOperand* tmp = temporary(c);
|
|
|
|
tmp->accept(c, mov, this);
|
|
|
|
tmp->release(c);
|
|
|
|
return tmp->value;
|
|
|
|
}
|
|
|
|
|
2007-12-12 22:19:13 +00:00
|
|
|
void
|
|
|
|
absoluteApply(Context* c, MyOperand::Operation operation,
|
|
|
|
AbsoluteOperand* operand)
|
|
|
|
{
|
|
|
|
RegisterOperand* tmp = temporary(c);
|
2007-12-14 00:27:09 +00:00
|
|
|
tmp->accept(c, MyOperand::mov, value(c, operand));
|
2007-12-12 22:19:13 +00:00
|
|
|
memory(c, tmp, 0, 0, 1)->apply(c, operation);
|
|
|
|
tmp->release(c);
|
|
|
|
}
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
void
|
|
|
|
AbsoluteOperand::apply(Context* c, Operation operation)
|
|
|
|
{
|
|
|
|
switch (operation) {
|
2007-12-12 22:19:13 +00:00
|
|
|
case push:
|
|
|
|
absoluteApply(c, operation, this);
|
|
|
|
break;
|
2007-12-12 18:59:45 +00:00
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
default: abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-12 18:59:45 +00:00
|
|
|
Register
|
|
|
|
MemoryOperand::asRegister(Context* c)
|
2007-12-11 21:26:59 +00:00
|
|
|
{
|
2007-12-12 18:59:45 +00:00
|
|
|
RegisterOperand* tmp = temporary(c);
|
2007-12-11 21:26:59 +00:00
|
|
|
tmp->accept(c, mov, this);
|
2007-12-12 18:59:45 +00:00
|
|
|
tmp->release(c);
|
|
|
|
return tmp->value;
|
2007-12-11 21:26:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MemoryOperand::apply(Context* c, Operation operation)
|
|
|
|
{
|
2007-12-16 21:30:19 +00:00
|
|
|
assert(c, operation == push or selection == DefaultSelection);
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
switch (operation) {
|
2007-12-12 01:19:03 +00:00
|
|
|
case call:
|
2007-12-14 01:59:56 +00:00
|
|
|
encode(c, 0xff, 2, this, false);
|
|
|
|
break;
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
case jmp:
|
|
|
|
encode(c, 0xff, 4, this, false);
|
|
|
|
break;
|
|
|
|
|
2007-12-14 01:59:56 +00:00
|
|
|
case neg:
|
|
|
|
encode(c, 0xf7, 2, this, true);
|
2007-12-12 01:19:03 +00:00
|
|
|
break;
|
|
|
|
|
2007-12-11 23:52:28 +00:00
|
|
|
case pop:
|
2007-12-14 01:59:56 +00:00
|
|
|
encode(c, 0x8f, 0, this, false);
|
2007-12-11 23:52:28 +00:00
|
|
|
break;
|
|
|
|
|
2007-12-12 18:59:45 +00:00
|
|
|
case push:
|
2007-12-16 21:30:19 +00:00
|
|
|
if (selection == DefaultSelection) {
|
|
|
|
encode(c, 0xff, 6, this, false);
|
|
|
|
} else {
|
|
|
|
RegisterOperand* tmp = temporary(c);
|
|
|
|
tmp->accept(c, mov, this);
|
|
|
|
tmp->apply(c, operation);
|
|
|
|
tmp->release(c);
|
|
|
|
}
|
2007-12-12 18:59:45 +00:00
|
|
|
break;
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
default: abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MemoryOperand::accept(Context* c, Operation operation,
|
|
|
|
RegisterOperand* operand)
|
|
|
|
{
|
2007-12-16 21:30:19 +00:00
|
|
|
assert(c, operation == mov or selection == DefaultSelection);
|
|
|
|
assert(c, operand->selection == DefaultSelection);
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
switch (operation) {
|
2007-12-16 00:24:15 +00:00
|
|
|
case and_: {
|
|
|
|
encode(c, 0x21, operand->value, this, true);
|
|
|
|
} break;
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
case add: {
|
2007-12-14 01:59:56 +00:00
|
|
|
encode(c, 0x01, operand->value, this, true);
|
2007-12-14 00:27:09 +00:00
|
|
|
} break;
|
2007-12-12 22:19:13 +00:00
|
|
|
|
2007-12-14 18:27:56 +00:00
|
|
|
case div: {
|
2007-12-16 21:30:19 +00:00
|
|
|
RegisterOperand* ax = temporary(c, rax);
|
|
|
|
RegisterOperand* dx = temporary(c, rdx);
|
|
|
|
ax->accept(c, mov, this);
|
2007-12-14 18:27:56 +00:00
|
|
|
|
|
|
|
rex(c);
|
|
|
|
c->code.append(0x99);
|
|
|
|
rex(c);
|
|
|
|
c->code.append(0xf7);
|
|
|
|
c->code.append(0xf8 | operand->value);
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
accept(c, mov, ax);
|
|
|
|
|
|
|
|
ax->release(c);
|
|
|
|
dx->release(c);
|
2007-12-14 18:27:56 +00:00
|
|
|
} break;
|
2007-12-14 01:59:56 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
case mov: {
|
2007-12-16 21:30:19 +00:00
|
|
|
if (selection == DefaultSelection) {
|
|
|
|
encode(c, 0x89, operand->value, this, true);
|
|
|
|
} else {
|
|
|
|
switch (selection) {
|
|
|
|
case S1Selection:
|
2007-12-16 23:52:38 +00:00
|
|
|
if (operand->value > rbx) {
|
|
|
|
c->code.append(0x40);
|
|
|
|
}
|
|
|
|
encode(c, 0x88, operand->value, this, false);
|
2007-12-16 21:30:19 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case S2Selection:
|
|
|
|
case Z2Selection:
|
|
|
|
c->code.append(0x66);
|
|
|
|
encode(c, 0x89, operand->value, this, false);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case S4Selection:
|
|
|
|
encode(c, 0x89, operand->value, this, false);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
2007-12-16 23:52:38 +00:00
|
|
|
case mul: {
|
|
|
|
RegisterOperand* tmp = temporary(c);
|
|
|
|
|
|
|
|
tmp->accept(c, mov, this);
|
|
|
|
tmp->accept(c, mul, operand);
|
|
|
|
accept(c, mov, tmp);
|
|
|
|
|
|
|
|
tmp->release(c);
|
|
|
|
} break;
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
case rem: {
|
|
|
|
RegisterOperand* ax = temporary(c, rax);
|
|
|
|
RegisterOperand* dx = temporary(c, rdx);
|
|
|
|
ax->accept(c, mov, this);
|
|
|
|
|
|
|
|
rex(c);
|
|
|
|
c->code.append(0x99);
|
|
|
|
rex(c);
|
|
|
|
c->code.append(0xf7);
|
|
|
|
c->code.append(0xf8 | operand->value);
|
|
|
|
|
|
|
|
accept(c, mov, dx);
|
|
|
|
|
|
|
|
ax->release(c);
|
|
|
|
dx->release(c);
|
2007-12-14 00:27:09 +00:00
|
|
|
} break;
|
2007-12-11 21:26:59 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
case sub: {
|
2007-12-14 01:59:56 +00:00
|
|
|
encode(c, 0x29, operand->value, this, true);
|
2007-12-14 00:27:09 +00:00
|
|
|
} break;
|
2007-12-12 18:59:45 +00:00
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
default: abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MemoryOperand::accept(Context* c, Operation operation,
|
|
|
|
ImmediateOperand* operand)
|
|
|
|
{
|
2007-12-16 21:30:19 +00:00
|
|
|
assert(c, selection == DefaultSelection);
|
|
|
|
assert(c, operand->selection == DefaultSelection);
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
switch (operation) {
|
2007-12-12 22:19:13 +00:00
|
|
|
case add: {
|
2007-12-14 00:27:09 +00:00
|
|
|
unsigned i = (isInt8(operand->value) ? 0x83 : 0x81);
|
|
|
|
|
2007-12-14 01:59:56 +00:00
|
|
|
encode(c, i, 0, this, true);
|
2007-12-14 00:27:09 +00:00
|
|
|
if (isInt8(operand->value)) {
|
|
|
|
c->code.append(operand->value);
|
|
|
|
} else if (isInt32(operand->value)) {
|
|
|
|
c->code.append4(operand->value);
|
2007-12-12 22:19:13 +00:00
|
|
|
} else {
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case mov: {
|
2007-12-14 00:27:09 +00:00
|
|
|
assert(c, isInt32(operand->value)); // todo
|
2007-12-11 21:26:59 +00:00
|
|
|
|
2007-12-14 01:59:56 +00:00
|
|
|
encode(c, 0xc7, 0, this, true);
|
2007-12-14 00:27:09 +00:00
|
|
|
c->code.append4(operand->value);
|
2007-12-12 22:19:13 +00:00
|
|
|
} break;
|
2007-12-11 21:26:59 +00:00
|
|
|
|
|
|
|
default: abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-12 00:27:04 +00:00
|
|
|
void
|
|
|
|
MemoryOperand::accept(Context* c, Operation operation,
|
|
|
|
AbsoluteOperand* operand)
|
|
|
|
{
|
2007-12-16 21:30:19 +00:00
|
|
|
RegisterOperand* tmp = temporary(c);
|
2007-12-12 00:27:04 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
tmp->accept(c, mov, operand);
|
|
|
|
accept(c, operation, tmp);
|
2007-12-12 00:27:04 +00:00
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
tmp->release(c);
|
2007-12-12 00:27:04 +00:00
|
|
|
}
|
|
|
|
|
2007-12-14 18:27:56 +00:00
|
|
|
void
|
|
|
|
MemoryOperand::accept(Context* c, Operation operation,
|
2007-12-16 21:30:19 +00:00
|
|
|
MemoryOperand* operand)
|
2007-12-14 18:27:56 +00:00
|
|
|
{
|
2007-12-16 21:30:19 +00:00
|
|
|
RegisterOperand* tmp = temporary(c);
|
|
|
|
|
|
|
|
tmp->accept(c, mov, operand);
|
|
|
|
accept(c, operation, tmp);
|
|
|
|
|
|
|
|
tmp->release(c);
|
2007-12-14 18:27:56 +00:00
|
|
|
}
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
int
|
|
|
|
compareSegmentPointers(const void* a, const void* b)
|
2007-12-11 23:52:28 +00:00
|
|
|
{
|
2007-12-14 00:27:09 +00:00
|
|
|
return (*static_cast<Segment* const*>(a))->logicalIp
|
|
|
|
- (*static_cast<Segment* const*>(b))->logicalIp;
|
2007-12-11 23:52:28 +00:00
|
|
|
}
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
void
|
|
|
|
writeCode(Context* c)
|
2007-12-12 22:19:13 +00:00
|
|
|
{
|
2007-12-14 00:27:09 +00:00
|
|
|
unsigned tableSize = (c->plan.length() / BytesPerWord);
|
2007-12-12 22:19:13 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
if (c->codeLength < 0) {
|
|
|
|
c->segmentTable = static_cast<Segment**>(c->s->allocate(c->plan.length()));
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < tableSize; ++i) {
|
|
|
|
c->plan.get(i * BytesPerWord, c->segmentTable + i, BytesPerWord);
|
2007-12-12 22:19:13 +00:00
|
|
|
}
|
2007-12-14 00:27:09 +00:00
|
|
|
|
|
|
|
qsort(c->segmentTable, tableSize, BytesPerWord, compareSegmentPointers);
|
2007-12-11 23:52:28 +00:00
|
|
|
}
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
for (unsigned i = 0; i < tableSize; ++i) {
|
|
|
|
Segment* s = c->segmentTable[i];
|
2007-12-16 21:30:19 +00:00
|
|
|
if (Verbose) {
|
2007-12-14 18:27:56 +00:00
|
|
|
fprintf(stderr, "\nip %d\n", s->logicalIp);
|
|
|
|
}
|
2007-12-15 01:11:01 +00:00
|
|
|
|
|
|
|
if (c->codeLength >= 0) {
|
|
|
|
assert(c, s->offset == static_cast<int>(c->code.length()));
|
|
|
|
} else {
|
|
|
|
s->offset = c->code.length();
|
|
|
|
}
|
2007-12-14 18:27:56 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
Event* events[s->event->count];
|
|
|
|
unsigned ei = s->event->count;
|
|
|
|
for (Event* e = s->event; e; e = e->next) {
|
|
|
|
events[--ei] = e;
|
|
|
|
}
|
2007-12-11 23:52:28 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
for (unsigned ei = 0; ei < s->event->count; ++ei) {
|
2007-12-16 21:30:19 +00:00
|
|
|
if (Verbose and ei) {
|
2007-12-14 18:27:56 +00:00
|
|
|
fprintf(stderr, "address %p\n", c->code.data + c->code.length());
|
|
|
|
}
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
events[ei]->run(c);
|
|
|
|
|
|
|
|
if (c->codeLength < 0) {
|
|
|
|
for (Task* t = events[ei]->task; t; t = t->next) {
|
|
|
|
t->run(c, c->code.length());
|
2007-12-12 22:19:13 +00:00
|
|
|
}
|
2007-12-11 23:52:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
c->codeLength = pad(c->code.length());
|
2007-12-11 23:52:28 +00:00
|
|
|
}
|
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
class CodePromiseTask: public Task {
|
|
|
|
public:
|
|
|
|
CodePromiseTask(CodePromise* promise, Task* next):
|
|
|
|
Task(next), promise(promise)
|
|
|
|
{ }
|
2007-12-11 23:52:28 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
virtual void run(Context* c UNUSED, unsigned offset) {
|
|
|
|
promise->offset = offset;
|
2007-12-11 23:52:28 +00:00
|
|
|
}
|
2007-12-14 00:27:09 +00:00
|
|
|
|
|
|
|
CodePromise* promise;
|
|
|
|
};
|
2007-12-11 23:52:28 +00:00
|
|
|
|
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
|
|
|
{ }
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
virtual Promise* machineIp() {
|
|
|
|
CodePromise* p = new (c.zone.allocate(sizeof(CodePromise))) CodePromise();
|
2007-12-11 21:26:59 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
Segment* s = currentSegment(&c);
|
|
|
|
s->event->task = new (c.zone.allocate(sizeof(CodePromiseTask)))
|
|
|
|
CodePromiseTask(p, s->event->task);
|
2007-12-11 21:26:59 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
return p;
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
virtual Promise* machineIp(unsigned logicalIp) {
|
|
|
|
return new (c.zone.allocate(sizeof(IpPromise))) IpPromise(logicalIp);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Promise* poolAppend(intptr_t v) {
|
|
|
|
return poolAppendPromise
|
|
|
|
(new (c.zone.allocate(sizeof(ResolvedPromise))) ResolvedPromise(v));
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Promise* poolAppendPromise(Promise* v) {
|
|
|
|
Promise* p = new (c.zone.allocate(sizeof(PoolPromise)))
|
|
|
|
PoolPromise(c.constantPool.length());
|
2007-12-11 00:48:09 +00:00
|
|
|
c.constantPool.appendAddress(v);
|
2007-12-16 00:24:15 +00:00
|
|
|
return p;
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
virtual Operand* constant(int64_t v) {
|
2007-12-09 20:03:21 +00:00
|
|
|
return immediate(&c, v);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
virtual Operand* promiseConstant(Promise* p) {
|
|
|
|
return address(&c, static_cast<MyPromise*>(p));
|
2007-12-12 22:19:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
virtual Operand* absolute(Promise* p) {
|
|
|
|
return ::absolute(&c, static_cast<MyPromise*>(p));
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
virtual Stack* push(Stack* s, unsigned count) {
|
|
|
|
return ::push(&c, static_cast<MyStack*>(s), count);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
virtual Stack* push(Stack* s, Operand* v) {
|
|
|
|
return ::push(&c, static_cast<MyStack*>(s), static_cast<MyOperand*>(v));
|
|
|
|
}
|
2007-12-08 23:22:13 +00:00
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
virtual Operand* stack(Stack* s, unsigned index) {
|
|
|
|
MyStack* stack = static_cast<MyStack*>(s);
|
|
|
|
unsigned i = 0;
|
|
|
|
|
2007-12-16 21:30:19 +00:00
|
|
|
if (stack->value->footprint(&c) / BytesPerWord == 2) {
|
2007-12-16 00:24:15 +00:00
|
|
|
++ i;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; i < index; ++i) {
|
|
|
|
stack = stack->next;
|
2007-12-16 21:30:19 +00:00
|
|
|
if (stack->value->footprint(&c) / BytesPerWord == 2) {
|
2007-12-16 00:24:15 +00:00
|
|
|
++ i;
|
|
|
|
}
|
|
|
|
}
|
2007-12-12 22:19:13 +00:00
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
return stack->value;
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
virtual Stack* pop(Stack* s, unsigned count) {
|
|
|
|
return ::pop(&c, static_cast<MyStack*>(s), count);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
virtual Stack* pop(Stack* s, Operand* dst) {
|
|
|
|
return ::pop(&c, static_cast<MyStack*>(s), static_cast<MyOperand*>(dst));
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* stack() {
|
2007-12-09 20:03:21 +00:00
|
|
|
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-16 21:30:19 +00:00
|
|
|
RegisterReference* reference = new
|
|
|
|
(c.zone.allocate(sizeof(RegisterReference))) RegisterReference();
|
2007-12-14 00:27:09 +00:00
|
|
|
TemporaryOperand* r = new (c.zone.allocate(sizeof(TemporaryOperand)))
|
2007-12-16 21:30:19 +00:00
|
|
|
TemporaryOperand(reference, DefaultSelection);
|
2007-12-14 00:27:09 +00:00
|
|
|
appendAcquire(&c, r);
|
|
|
|
return r;
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void release(Operand* v) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendRelease(&c, v);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* label() {
|
2007-12-14 00:27:09 +00:00
|
|
|
return address(&c, 0);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void mark(Operand* label) {
|
2007-12-16 00:24:15 +00:00
|
|
|
static_cast<MyOperand*>(label)->setLabelValue
|
|
|
|
(&c, static_cast<MyPromise*>(machineIp()));
|
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-14 00:27:09 +00:00
|
|
|
mov(address, register_(&c, rax));
|
|
|
|
call(immediate(&c, c.indirectCaller));
|
2007-12-11 00:48:09 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
add(immediate(&c, footprint), 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-14 00:27:09 +00:00
|
|
|
mov(address, register_(&c, rax));
|
2007-12-11 00:48:09 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
call(immediate(&c, c.indirectCaller));
|
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-14 00:27:09 +00:00
|
|
|
call(address);
|
2007-12-08 23:22:13 +00:00
|
|
|
|
2007-12-14 00:27:09 +00:00
|
|
|
add(immediate(&c, footprint), 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-14 00:27:09 +00:00
|
|
|
mov(v, register_(&c, rax));
|
2007-12-12 18:59:45 +00:00
|
|
|
epilogue();
|
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) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::call, v);
|
2007-12-11 00:48:09 +00:00
|
|
|
return register_(&c, rax);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* alignedCall(Operand* v) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::alignedCall, v);
|
2007-12-11 00:48:09 +00:00
|
|
|
return register_(&c, rax);
|
|
|
|
}
|
|
|
|
|
2007-12-08 23:22:13 +00:00
|
|
|
virtual void ret() {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::ret);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void mov(Operand* src, Operand* dst) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::mov, src, dst);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void cmp(Operand* subtrahend, Operand* minuend) {
|
2007-12-14 18:27:56 +00:00
|
|
|
appendOperation(&c, MyOperand::cmp, subtrahend, minuend);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void jl(Operand* v) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::jl, v);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void jg(Operand* v) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::jg, v);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void jle(Operand* v) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::jle, v);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void jge(Operand* v) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::jge, v);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void je(Operand* v) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::je, v);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void jne(Operand* v) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::jne, v);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void jmp(Operand* v) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::jmp, v);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void add(Operand* v, Operand* dst) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::add, v, dst);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void sub(Operand* v, Operand* dst) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::sub, v, dst);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void mul(Operand* v, Operand* dst) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::mul, v, dst);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void div(Operand* v, Operand* dst) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::div, v, dst);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void rem(Operand* v, Operand* dst) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::rem, v, dst);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void shl(Operand* v, Operand* dst) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::shl, v, dst);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void shr(Operand* v, Operand* dst) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::shr, v, dst);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void ushr(Operand* v, Operand* dst) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::ushr, v, dst);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void and_(Operand* v, Operand* dst) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::and_, v, dst);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void or_(Operand* v, Operand* dst) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::or_, v, dst);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void xor_(Operand* v, Operand* dst) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::xor_, v, dst);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void neg(Operand* v) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::neg, v);
|
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) {
|
2007-12-16 21:30:19 +00:00
|
|
|
return static_cast<MyOperand*>(v)->select(&c, S1Selection);
|
2007-12-09 22:45:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* select2(Operand* v) {
|
2007-12-16 21:30:19 +00:00
|
|
|
return static_cast<MyOperand*>(v)->select(&c, S2Selection);
|
2007-12-09 22:45:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* select2z(Operand* v) {
|
2007-12-16 21:30:19 +00:00
|
|
|
return static_cast<MyOperand*>(v)->select(&c, Z2Selection);
|
2007-12-09 22:45:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* select4(Operand* v) {
|
2007-12-16 21:30:19 +00:00
|
|
|
return static_cast<MyOperand*>(v)->select(&c, S4Selection);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-09 22:45:43 +00:00
|
|
|
virtual Operand* select8(Operand* v) {
|
2007-12-16 21:30:19 +00:00
|
|
|
return static_cast<MyOperand*>(v)->select(&c, S8Selection);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void prologue() {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation(&c, MyOperand::push, register_(&c, rbp));
|
|
|
|
appendOperation
|
|
|
|
(&c, MyOperand::mov, register_(&c, rsp), register_(&c, rbp));
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-12 18:59:45 +00:00
|
|
|
virtual void reserve(unsigned size) {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation
|
|
|
|
(&c, MyOperand::sub, immediate(&c, size * BytesPerWord),
|
|
|
|
register_(&c, rsp));
|
|
|
|
|
2007-12-12 18:59:45 +00:00
|
|
|
c.reserved = size;
|
|
|
|
}
|
|
|
|
|
2007-12-08 23:22:13 +00:00
|
|
|
virtual void epilogue() {
|
2007-12-14 00:27:09 +00:00
|
|
|
appendOperation
|
|
|
|
(&c, MyOperand::mov, register_(&c, rbp), register_(&c, rsp));
|
|
|
|
appendOperation(&c, MyOperand::pop, register_(&c, rbp));
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-09 20:03:21 +00:00
|
|
|
virtual void startLogicalIp(unsigned ip) {
|
2007-12-14 00:27:09 +00:00
|
|
|
c.plan.appendAddress
|
|
|
|
(new (c.zone.allocate(sizeof(Segment)))
|
|
|
|
Segment(ip, new (c.zone.allocate(sizeof(Event))) Event(0)));
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-11 23:52:28 +00:00
|
|
|
virtual unsigned codeSize() {
|
2007-12-14 00:27:09 +00:00
|
|
|
if (c.codeLength < 0) {
|
|
|
|
assert(&c, c.code.length() == 0);
|
|
|
|
writeCode(&c);
|
|
|
|
}
|
|
|
|
return c.codeLength;
|
2007-12-11 23:52:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual unsigned poolSize() {
|
|
|
|
return c.constantPool.length();
|
2007-12-11 00:48:09 +00:00
|
|
|
}
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
virtual void writeTo(uint8_t* out) {
|
2007-12-14 00:27:09 +00:00
|
|
|
c.code.wrap(out, codeSize());
|
|
|
|
writeCode(&c);
|
2007-12-11 23:52:28 +00:00
|
|
|
|
2007-12-16 00:24:15 +00:00
|
|
|
for (unsigned i = 0; i < c.constantPool.length(); i += BytesPerWord) {
|
|
|
|
Promise* p; c.constantPool.get(i, &p, BytesPerWord);
|
|
|
|
*reinterpret_cast<intptr_t*>(out + codeSize() + i) = p->value(this);
|
|
|
|
}
|
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);
|
2007-12-11 23:52:28 +00:00
|
|
|
assert(&c, reinterpret_cast<uintptr_t>(instruction + 1) % 4 == 0);
|
2007-12-11 00:48:09 +00:00
|
|
|
|
|
|
|
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-12 22:19:13 +00:00
|
|
|
intptr_t
|
2007-12-11 23:52:28 +00:00
|
|
|
MyPromise::value(Compiler* compiler)
|
2007-12-11 00:48:09 +00:00
|
|
|
{
|
2007-12-11 23:52:28 +00:00
|
|
|
return value(&(static_cast<MyCompiler*>(compiler)->c));
|
2007-12-11 00:48:09 +00:00
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-12-12 00:08:55 +00:00
|
|
|
} // namespace v
|