mirror of
https://github.com/corda/corda.git
synced 2025-01-04 04:04:27 +00:00
further split up compiler.cpp
This commit is contained in:
parent
952cad2360
commit
b0abc4e1e5
3
makefile
3
makefile
@ -953,10 +953,11 @@ embed-objects = $(call cpp-objects,$(embed-sources),$(src),$(build-embed))
|
||||
ifeq ($(process),compile)
|
||||
vm-sources += \
|
||||
$(src)/codegen/compiler.cpp \
|
||||
$(src)/codegen/regalloc.cpp \
|
||||
$(src)/codegen/compiler/context.cpp \
|
||||
$(src)/codegen/compiler/resource.cpp \
|
||||
$(src)/codegen/compiler/site.cpp \
|
||||
$(src)/codegen/compiler/regalloc.cpp \
|
||||
$(src)/codegen/compiler/value.cpp \
|
||||
$(src)/codegen/registers.cpp \
|
||||
$(src)/codegen/targets.cpp
|
||||
|
||||
|
@ -14,12 +14,13 @@
|
||||
|
||||
#include "codegen/compiler.h"
|
||||
#include "codegen/assembler.h"
|
||||
#include "codegen/regalloc.h"
|
||||
|
||||
#include "codegen/compiler/regalloc.h"
|
||||
#include "codegen/compiler/context.h"
|
||||
#include "codegen/compiler/resource.h"
|
||||
#include "codegen/compiler/value.h"
|
||||
#include "codegen/compiler/site.h"
|
||||
#include "codegen/compiler/read.h"
|
||||
|
||||
using namespace vm;
|
||||
|
||||
@ -156,29 +157,6 @@ class ConstantPoolNode {
|
||||
ConstantPoolNode* next;
|
||||
};
|
||||
|
||||
class Read {
|
||||
public:
|
||||
Read():
|
||||
value(0), event(0), eventNext(0)
|
||||
{ }
|
||||
|
||||
virtual bool intersect(SiteMask* mask, unsigned depth = 0) = 0;
|
||||
|
||||
virtual Value* high(Context* c) { abort(c); }
|
||||
|
||||
virtual Value* successor() = 0;
|
||||
|
||||
virtual bool valid() = 0;
|
||||
|
||||
virtual void append(Context* c, Read* r) = 0;
|
||||
|
||||
virtual Read* next(Context* c) = 0;
|
||||
|
||||
Value* value;
|
||||
Event* event;
|
||||
Read* eventNext;
|
||||
};
|
||||
|
||||
int
|
||||
intersectFrameIndexes(int a, int b)
|
||||
{
|
||||
@ -524,15 +502,6 @@ hasSite(Context* c, Value* v)
|
||||
return it.hasMore();
|
||||
}
|
||||
|
||||
bool
|
||||
findSite(Context*, Value* v, Site* site)
|
||||
{
|
||||
for (Site* s = v->sites; s; s = s->next) {
|
||||
if (s == site) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
uniqueSite(Context* c, Value* v, Site* s)
|
||||
{
|
||||
@ -561,7 +530,7 @@ uniqueSite(Context* c, Value* v, Site* s)
|
||||
void
|
||||
addSite(Context* c, Value* v, Site* s)
|
||||
{
|
||||
if (not findSite(c, v, s)) {
|
||||
if (not v->findSite(s)) {
|
||||
if (DebugSites) {
|
||||
char buffer[256]; s->toString(c, buffer, 256);
|
||||
fprintf(stderr, "add site %s to %p\n", buffer, v);
|
||||
@ -588,7 +557,7 @@ removeSite(Context* c, Value* v, Site* s)
|
||||
if (DebugSites) {
|
||||
fprintf(stderr, "%p has more: %d\n", v, hasSite(c, v));
|
||||
}
|
||||
assert(c, not findSite(c, v, s));
|
||||
assert(c, not v->findSite(s));
|
||||
}
|
||||
|
||||
void
|
||||
@ -745,16 +714,6 @@ popRead(Context* c, Event* e UNUSED, Value* v)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
buddies(Value* a, Value* b)
|
||||
{
|
||||
if (a == b) return true;
|
||||
for (Value* p = a->buddy; p != a; p = p->buddy) {
|
||||
if (p == b) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
addBuddy(Value* original, Value* buddy)
|
||||
{
|
||||
@ -772,27 +731,6 @@ addBuddy(Value* original, Value* buddy)
|
||||
}
|
||||
}
|
||||
|
||||
class Target {
|
||||
public:
|
||||
static const unsigned MinimumRegisterCost = 0;
|
||||
static const unsigned MinimumFrameCost = 1;
|
||||
static const unsigned StealPenalty = 2;
|
||||
static const unsigned StealUniquePenalty = 4;
|
||||
static const unsigned IndirectMovePenalty = 4;
|
||||
static const unsigned LowRegisterPenalty = 10;
|
||||
static const unsigned Impossible = 20;
|
||||
|
||||
Target(): cost(Impossible) { }
|
||||
|
||||
Target(int index, lir::OperandType type, unsigned cost):
|
||||
index(index), type(type), cost(cost)
|
||||
{ }
|
||||
|
||||
int16_t index;
|
||||
lir::OperandType type;
|
||||
uint8_t cost;
|
||||
};
|
||||
|
||||
lir::ValueType
|
||||
valueType(Context* c, Compiler::OperandType type)
|
||||
{
|
||||
@ -809,283 +747,6 @@ valueType(Context* c, Compiler::OperandType type)
|
||||
}
|
||||
}
|
||||
|
||||
class CostCalculator {
|
||||
public:
|
||||
virtual unsigned cost(Context* c, SiteMask mask) = 0;
|
||||
};
|
||||
|
||||
unsigned
|
||||
resourceCost(Context* c, Value* v, Resource* r, SiteMask mask,
|
||||
CostCalculator* costCalculator)
|
||||
{
|
||||
if (r->reserved or r->freezeCount or r->referenceCount) {
|
||||
return Target::Impossible;
|
||||
} else {
|
||||
unsigned baseCost =
|
||||
costCalculator ? costCalculator->cost(c, mask) : 0;
|
||||
|
||||
if (r->value) {
|
||||
assert(c, findSite(c, r->value, r->site));
|
||||
|
||||
if (v and buddies(r->value, v)) {
|
||||
return baseCost;
|
||||
} else if (uniqueSite(c, r->value, r->site)) {
|
||||
return baseCost + Target::StealUniquePenalty;
|
||||
} else {
|
||||
return baseCost = Target::StealPenalty;
|
||||
}
|
||||
} else {
|
||||
return baseCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
pickRegisterTarget(Context* c, int i, Value* v, uint32_t mask, int* target,
|
||||
unsigned* cost, CostCalculator* costCalculator = 0)
|
||||
{
|
||||
if ((1 << i) & mask) {
|
||||
RegisterResource* r = c->registerResources + i;
|
||||
unsigned myCost = resourceCost
|
||||
(c, v, r, SiteMask(1 << lir::RegisterOperand, 1 << i, NoFrameIndex), costCalculator)
|
||||
+ Target::MinimumRegisterCost;
|
||||
|
||||
if ((static_cast<uint32_t>(1) << i) == mask) {
|
||||
*cost = myCost;
|
||||
return true;
|
||||
} else if (myCost < *cost) {
|
||||
*cost = myCost;
|
||||
*target = i;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
pickRegisterTarget(Context* c, Value* v, uint32_t mask, unsigned* cost,
|
||||
CostCalculator* costCalculator = 0)
|
||||
{
|
||||
int target = lir::NoRegister;
|
||||
*cost = Target::Impossible;
|
||||
|
||||
if (mask & c->regFile->generalRegisters.mask) {
|
||||
for (int i = c->regFile->generalRegisters.limit - 1;
|
||||
i >= c->regFile->generalRegisters.start; --i)
|
||||
{
|
||||
if (pickRegisterTarget(c, i, v, mask, &target, cost, costCalculator)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & c->regFile->floatRegisters.mask) {
|
||||
for (int i = c->regFile->floatRegisters.start;
|
||||
i < static_cast<int>(c->regFile->floatRegisters.limit); ++i)
|
||||
{
|
||||
if (pickRegisterTarget(c, i, v, mask, &target, cost, costCalculator)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
Target
|
||||
pickRegisterTarget(Context* c, Value* v, uint32_t mask,
|
||||
CostCalculator* costCalculator = 0)
|
||||
{
|
||||
unsigned cost;
|
||||
int number = pickRegisterTarget(c, v, mask, &cost, costCalculator);
|
||||
return Target(number, lir::RegisterOperand, cost);
|
||||
}
|
||||
|
||||
unsigned
|
||||
frameCost(Context* c, Value* v, int frameIndex, CostCalculator* costCalculator)
|
||||
{
|
||||
return resourceCost
|
||||
(c, v, c->frameResources + frameIndex, SiteMask(1 << lir::MemoryOperand, 0, frameIndex),
|
||||
costCalculator)
|
||||
+ Target::MinimumFrameCost;
|
||||
}
|
||||
|
||||
Target
|
||||
pickFrameTarget(Context* c, Value* v, CostCalculator* costCalculator)
|
||||
{
|
||||
Target best;
|
||||
|
||||
Value* p = v;
|
||||
do {
|
||||
if (p->home >= 0) {
|
||||
Target mine
|
||||
(p->home, lir::MemoryOperand, frameCost(c, v, p->home, costCalculator));
|
||||
|
||||
if (mine.cost == Target::MinimumFrameCost) {
|
||||
return mine;
|
||||
} else if (mine.cost < best.cost) {
|
||||
best = mine;
|
||||
}
|
||||
}
|
||||
p = p->buddy;
|
||||
} while (p != v);
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
Target
|
||||
pickAnyFrameTarget(Context* c, Value* v, CostCalculator* costCalculator)
|
||||
{
|
||||
Target best;
|
||||
|
||||
unsigned count = totalFrameSize(c);
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
Target mine(i, lir::MemoryOperand, frameCost(c, v, i, costCalculator));
|
||||
if (mine.cost == Target::MinimumFrameCost) {
|
||||
return mine;
|
||||
} else if (mine.cost < best.cost) {
|
||||
best = mine;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
Target
|
||||
pickTarget(Context* c, Value* value, const SiteMask& mask,
|
||||
unsigned registerPenalty, Target best,
|
||||
CostCalculator* costCalculator)
|
||||
{
|
||||
if (mask.typeMask & (1 << lir::RegisterOperand)) {
|
||||
Target mine = pickRegisterTarget
|
||||
(c, value, mask.registerMask, costCalculator);
|
||||
|
||||
mine.cost += registerPenalty;
|
||||
if (mine.cost == Target::MinimumRegisterCost) {
|
||||
return mine;
|
||||
} else if (mine.cost < best.cost) {
|
||||
best = mine;
|
||||
}
|
||||
}
|
||||
|
||||
if (mask.typeMask & (1 << lir::MemoryOperand)) {
|
||||
if (mask.frameIndex >= 0) {
|
||||
Target mine(mask.frameIndex, lir::MemoryOperand,
|
||||
frameCost(c, value, mask.frameIndex, costCalculator));
|
||||
if (mine.cost == Target::MinimumFrameCost) {
|
||||
return mine;
|
||||
} else if (mine.cost < best.cost) {
|
||||
best = mine;
|
||||
}
|
||||
} else if (mask.frameIndex == AnyFrameIndex) {
|
||||
Target mine = pickFrameTarget(c, value, costCalculator);
|
||||
if (mine.cost == Target::MinimumFrameCost) {
|
||||
return mine;
|
||||
} else if (mine.cost < best.cost) {
|
||||
best = mine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
Target
|
||||
pickTarget(Context* c, Read* read, bool intersectRead,
|
||||
unsigned registerReserveCount, CostCalculator* costCalculator)
|
||||
{
|
||||
unsigned registerPenalty
|
||||
= (c->availableGeneralRegisterCount > registerReserveCount
|
||||
? 0 : Target::LowRegisterPenalty);
|
||||
|
||||
Value* value = read->value;
|
||||
|
||||
uint32_t registerMask
|
||||
= (value->type == lir::ValueFloat ? ~0 : c->regFile->generalRegisters.mask);
|
||||
|
||||
SiteMask mask(~0, registerMask, AnyFrameIndex);
|
||||
read->intersect(&mask);
|
||||
|
||||
if (value->type == lir::ValueFloat) {
|
||||
uint32_t floatMask = mask.registerMask & c->regFile->floatRegisters.mask;
|
||||
if (floatMask) {
|
||||
mask.registerMask = floatMask;
|
||||
}
|
||||
}
|
||||
|
||||
Target best;
|
||||
|
||||
Value* successor = read->successor();
|
||||
if (successor) {
|
||||
Read* r = live(c, successor);
|
||||
if (r) {
|
||||
SiteMask intersection = mask;
|
||||
if (r->intersect(&intersection)) {
|
||||
best = pickTarget
|
||||
(c, value, intersection, registerPenalty, best, costCalculator);
|
||||
|
||||
if (best.cost <= Target::MinimumFrameCost) {
|
||||
return best;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
best = pickTarget(c, value, mask, registerPenalty, best, costCalculator);
|
||||
if (best.cost <= Target::MinimumFrameCost) {
|
||||
return best;
|
||||
}
|
||||
|
||||
if (intersectRead) {
|
||||
if (best.cost == Target::Impossible) {
|
||||
fprintf(stderr, "mask type %d reg %d frame %d\n",
|
||||
mask.typeMask, mask.registerMask, mask.frameIndex);
|
||||
abort(c);
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
{ Target mine = pickRegisterTarget(c, value, registerMask, costCalculator);
|
||||
|
||||
mine.cost += registerPenalty;
|
||||
|
||||
if (mine.cost == Target::MinimumRegisterCost) {
|
||||
return mine;
|
||||
} else if (mine.cost < best.cost) {
|
||||
best = mine;
|
||||
}
|
||||
}
|
||||
|
||||
{ Target mine = pickFrameTarget(c, value, costCalculator);
|
||||
if (mine.cost == Target::MinimumFrameCost) {
|
||||
return mine;
|
||||
} else if (mine.cost < best.cost) {
|
||||
best = mine;
|
||||
}
|
||||
}
|
||||
|
||||
if (best.cost >= Target::StealUniquePenalty
|
||||
and c->availableGeneralRegisterCount == 0)
|
||||
{
|
||||
// there are no free registers left, so moving from memory to
|
||||
// memory isn't an option - try harder to find an available frame
|
||||
// site:
|
||||
best = pickAnyFrameTarget(c, value, costCalculator);
|
||||
assert(c, best.cost <= 3);
|
||||
}
|
||||
|
||||
if (best.cost == Target::Impossible) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
void
|
||||
acquire(Context* c, Resource* resource, Value* value, Site* site);
|
||||
|
||||
void
|
||||
release(Context* c, Resource* resource, Value* value, Site* site);
|
||||
|
||||
Promise* shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask) {
|
||||
return new(c->zone) ShiftMaskPromise(base, shift, mask);
|
||||
}
|
||||
@ -1094,297 +755,10 @@ Promise* combinedPromise(Context* c, Promise* low, Promise* high) {
|
||||
return new(c->zone) CombinedPromise(low, high);
|
||||
}
|
||||
|
||||
Promise*
|
||||
resolved(Context* c, int64_t value)
|
||||
{
|
||||
Promise* resolved(Context* c, int64_t value) {
|
||||
return new(c->zone) ResolvedPromise(value);
|
||||
}
|
||||
|
||||
AddressSite*
|
||||
addressSite(Context* c, Promise* address);
|
||||
|
||||
class AddressSite: public Site {
|
||||
public:
|
||||
AddressSite(Promise* address): address(address) { }
|
||||
|
||||
virtual unsigned toString(Context*, char* buffer, unsigned bufferSize) {
|
||||
if (address->resolved()) {
|
||||
return vm::snprintf
|
||||
(buffer, bufferSize, "address %" LLD, address->value());
|
||||
} else {
|
||||
return vm::snprintf(buffer, bufferSize, "address unresolved");
|
||||
}
|
||||
}
|
||||
|
||||
virtual unsigned copyCost(Context*, Site* s) {
|
||||
return (s == this ? 0 : AddressCopyCost);
|
||||
}
|
||||
|
||||
virtual bool match(Context*, const SiteMask& mask) {
|
||||
return mask.typeMask & (1 << lir::AddressOperand);
|
||||
}
|
||||
|
||||
virtual bool loneMatch(Context*, const SiteMask&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool matchNextWord(Context* c, Site*, unsigned) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
virtual lir::OperandType type(Context*) {
|
||||
return lir::AddressOperand;
|
||||
}
|
||||
|
||||
virtual void asAssemblerOperand(Context* c UNUSED, Site* high UNUSED,
|
||||
lir::Operand* result)
|
||||
{
|
||||
assert(c, high == this);
|
||||
|
||||
new (result) lir::Address(address);
|
||||
}
|
||||
|
||||
virtual Site* copy(Context* c) {
|
||||
return addressSite(c, address);
|
||||
}
|
||||
|
||||
virtual Site* copyLow(Context* c) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
virtual Site* copyHigh(Context* c) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
virtual Site* makeNextWord(Context* c, unsigned) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
virtual SiteMask mask(Context*) {
|
||||
return SiteMask(1 << lir::AddressOperand, 0, NoFrameIndex);
|
||||
}
|
||||
|
||||
virtual SiteMask nextWordMask(Context* c, unsigned) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
Promise* address;
|
||||
};
|
||||
|
||||
AddressSite*
|
||||
addressSite(Context* c, Promise* address)
|
||||
{
|
||||
return new(c->zone) AddressSite(address);
|
||||
}
|
||||
|
||||
RegisterSite*
|
||||
freeRegisterSite(Context* c, uint32_t mask);
|
||||
|
||||
class RegisterSite: public Site {
|
||||
public:
|
||||
RegisterSite(uint32_t mask, int number):
|
||||
mask_(mask), number(number)
|
||||
{ }
|
||||
|
||||
virtual unsigned toString(Context*, char* buffer, unsigned bufferSize) {
|
||||
if (number != lir::NoRegister) {
|
||||
return vm::snprintf(buffer, bufferSize, "%p register %d", this, number);
|
||||
} else {
|
||||
return vm::snprintf(buffer, bufferSize,
|
||||
"%p register unacquired (mask %d)", this, mask_);
|
||||
}
|
||||
}
|
||||
|
||||
virtual unsigned copyCost(Context* c, Site* s) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
if (s and
|
||||
(this == s or
|
||||
(s->type(c) == lir::RegisterOperand
|
||||
and (static_cast<RegisterSite*>(s)->mask_ & (1 << number)))))
|
||||
{
|
||||
return 0;
|
||||
} else {
|
||||
return RegisterCopyCost;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool match(Context* c UNUSED, const SiteMask& mask) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
if ((mask.typeMask & (1 << lir::RegisterOperand))) {
|
||||
return ((static_cast<uint64_t>(1) << number) & mask.registerMask);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool loneMatch(Context* c UNUSED, const SiteMask& mask) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
if ((mask.typeMask & (1 << lir::RegisterOperand))) {
|
||||
return ((static_cast<uint64_t>(1) << number) == mask.registerMask);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool matchNextWord(Context* c, Site* s, unsigned) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
if (s->type(c) != lir::RegisterOperand) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RegisterSite* rs = static_cast<RegisterSite*>(s);
|
||||
unsigned size = rs->registerSize(c);
|
||||
if (size > TargetBytesPerWord) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
return number == rs->number;
|
||||
} else {
|
||||
uint32_t mask = c->regFile->generalRegisters.mask;
|
||||
return ((1 << number) & mask) and ((1 << rs->number) & mask);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void acquire(Context* c, Value* v) {
|
||||
Target target;
|
||||
if (number != lir::NoRegister) {
|
||||
target = Target(number, lir::RegisterOperand, 0);
|
||||
} else {
|
||||
target = pickRegisterTarget(c, v, mask_);
|
||||
expect(c, target.cost < Target::Impossible);
|
||||
}
|
||||
|
||||
RegisterResource* resource = c->registerResources + target.index;
|
||||
compiler::acquire(c, resource, v, this);
|
||||
|
||||
number = target.index;
|
||||
}
|
||||
|
||||
virtual void release(Context* c, Value* v) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
compiler::release(c, c->registerResources + number, v, this);
|
||||
}
|
||||
|
||||
virtual void freeze(Context* c, Value* v) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
c->registerResources[number].freeze(c, v);
|
||||
}
|
||||
|
||||
virtual void thaw(Context* c, Value* v) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
c->registerResources[number].thaw(c, v);
|
||||
}
|
||||
|
||||
virtual bool frozen(Context* c UNUSED) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
return c->registerResources[number].freezeCount != 0;
|
||||
}
|
||||
|
||||
virtual lir::OperandType type(Context*) {
|
||||
return lir::RegisterOperand;
|
||||
}
|
||||
|
||||
virtual void asAssemblerOperand(Context* c UNUSED, Site* high,
|
||||
lir::Operand* result)
|
||||
{
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
int highNumber;
|
||||
if (high != this) {
|
||||
highNumber = static_cast<RegisterSite*>(high)->number;
|
||||
assert(c, highNumber != lir::NoRegister);
|
||||
} else {
|
||||
highNumber = lir::NoRegister;
|
||||
}
|
||||
|
||||
new (result) lir::Register(number, highNumber);
|
||||
}
|
||||
|
||||
virtual Site* copy(Context* c) {
|
||||
uint32_t mask;
|
||||
|
||||
if (number != lir::NoRegister) {
|
||||
mask = 1 << number;
|
||||
} else {
|
||||
mask = mask_;
|
||||
}
|
||||
|
||||
return freeRegisterSite(c, mask);
|
||||
}
|
||||
|
||||
virtual Site* copyLow(Context* c) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
virtual Site* copyHigh(Context* c) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
virtual Site* makeNextWord(Context* c, unsigned) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
assert(c, ((1 << number) & c->regFile->generalRegisters.mask));
|
||||
|
||||
return freeRegisterSite(c, c->regFile->generalRegisters.mask);
|
||||
}
|
||||
|
||||
virtual SiteMask mask(Context* c UNUSED) {
|
||||
return SiteMask(1 << lir::RegisterOperand, mask_, NoFrameIndex);
|
||||
}
|
||||
|
||||
virtual SiteMask nextWordMask(Context* c, unsigned) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
if (registerSize(c) > TargetBytesPerWord) {
|
||||
return SiteMask
|
||||
(1 << lir::RegisterOperand, number, NoFrameIndex);
|
||||
} else {
|
||||
return SiteMask
|
||||
(1 << lir::RegisterOperand, c->regFile->generalRegisters.mask, NoFrameIndex);
|
||||
}
|
||||
}
|
||||
|
||||
virtual unsigned registerSize(Context* c) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
if ((1 << number) & c->regFile->floatRegisters.mask) {
|
||||
return c->arch->floatRegisterSize();
|
||||
} else {
|
||||
return TargetBytesPerWord;
|
||||
}
|
||||
}
|
||||
|
||||
virtual unsigned registerMask(Context* c UNUSED) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
return 1 << number;
|
||||
}
|
||||
|
||||
uint32_t mask_;
|
||||
int number;
|
||||
};
|
||||
|
||||
RegisterSite*
|
||||
registerSite(Context* c, int number)
|
||||
{
|
||||
assert(c, number >= 0);
|
||||
assert(c, (1 << number) & (c->regFile->generalRegisters.mask
|
||||
| c->regFile->floatRegisters.mask));
|
||||
|
||||
return new(c->zone) RegisterSite(1 << number, number);
|
||||
}
|
||||
|
||||
RegisterSite*
|
||||
freeRegisterSite(Context* c, uint32_t mask)
|
||||
{
|
||||
return new(c->zone) RegisterSite(mask, lir::NoRegister);
|
||||
}
|
||||
|
||||
MemorySite*
|
||||
memorySite(Context* c, int base, int offset = 0, int index = lir::NoRegister,
|
||||
unsigned scale = 1);
|
||||
@ -1960,7 +1334,7 @@ steal(Context* c, Resource* r, Value* thief)
|
||||
thief, resourceBuffer, r->value, siteBuffer);
|
||||
}
|
||||
|
||||
if ((not (thief and buddies(thief, r->value))
|
||||
if ((not (thief and thief->isBuddyOf(r->value))
|
||||
and uniqueSite(c, r->value, r->site)))
|
||||
{
|
||||
r->site->freeze(c, r->value);
|
||||
@ -1973,71 +1347,6 @@ steal(Context* c, Resource* r, Value* thief)
|
||||
removeSite(c, r->value, r->site);
|
||||
}
|
||||
|
||||
void
|
||||
acquire(Context* c, Resource* resource, Value* value, Site* site)
|
||||
{
|
||||
assert(c, value);
|
||||
assert(c, site);
|
||||
|
||||
if (not resource->reserved) {
|
||||
if (DebugResources) {
|
||||
char buffer[256]; resource->toString(c, buffer, 256);
|
||||
fprintf(stderr, "%p acquire %s\n", value, buffer);
|
||||
}
|
||||
|
||||
if (resource->value) {
|
||||
assert(c, findSite(c, resource->value, resource->site));
|
||||
assert(c, not findSite(c, value, resource->site));
|
||||
|
||||
steal(c, resource, value);
|
||||
}
|
||||
|
||||
if (c->acquiredResources) {
|
||||
c->acquiredResources->previousAcquired = resource;
|
||||
resource->nextAcquired = c->acquiredResources;
|
||||
}
|
||||
c->acquiredResources = resource;
|
||||
|
||||
resource->value = value;
|
||||
resource->site = site;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
release(Context* c, Resource* resource, Value* value UNUSED, Site* site UNUSED)
|
||||
{
|
||||
if (not resource->reserved) {
|
||||
if (DebugResources) {
|
||||
char buffer[256]; resource->toString(c, buffer, 256);
|
||||
fprintf(stderr, "%p release %s\n", resource->value, buffer);
|
||||
}
|
||||
|
||||
assert(c, resource->value);
|
||||
assert(c, resource->site);
|
||||
|
||||
assert(c, buddies(resource->value, value));
|
||||
assert(c, site == resource->site);
|
||||
|
||||
Resource* next = resource->nextAcquired;
|
||||
if (next) {
|
||||
next->previousAcquired = resource->previousAcquired;
|
||||
resource->nextAcquired = 0;
|
||||
}
|
||||
|
||||
Resource* previous = resource->previousAcquired;
|
||||
if (previous) {
|
||||
previous->nextAcquired = next;
|
||||
resource->previousAcquired = 0;
|
||||
} else {
|
||||
assert(c, c->acquiredResources == resource);
|
||||
c->acquiredResources = next;
|
||||
}
|
||||
|
||||
resource->value = 0;
|
||||
resource->site = 0;
|
||||
}
|
||||
}
|
||||
|
||||
SiteMask
|
||||
generalRegisterMask(Context* c)
|
||||
{
|
||||
@ -2319,7 +1628,7 @@ move(Context* c, Value* value, Site* src, Site* dst)
|
||||
srcb, dstb, value, value);
|
||||
}
|
||||
|
||||
assert(c, findSite(c, value, dst));
|
||||
assert(c, value->findSite(dst));
|
||||
|
||||
src->freeze(c, value);
|
||||
dst->freeze(c, value);
|
||||
|
@ -12,9 +12,10 @@
|
||||
#define AVIAN_CODEGEN_COMPILER_CONTEXT_H
|
||||
|
||||
#include "codegen/assembler.h"
|
||||
#include "codegen/regalloc.h"
|
||||
#include "codegen/compiler.h"
|
||||
|
||||
#include "codegen/compiler/regalloc.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
@ -51,7 +52,7 @@ class Context {
|
||||
Event* predecessor;
|
||||
LogicalInstruction** logicalCode;
|
||||
const RegisterFile* regFile;
|
||||
regalloc::RegisterAllocator regAlloc;
|
||||
RegisterAllocator regAlloc;
|
||||
RegisterResource* registerResources;
|
||||
FrameResource* frameResources;
|
||||
Resource* acquiredResources;
|
||||
|
46
src/codegen/compiler/read.h
Normal file
46
src/codegen/compiler/read.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* Copyright (c) 2008-2012, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
#ifndef AVIAN_CODEGEN_COMPILER_READ_H
|
||||
#define AVIAN_CODEGEN_COMPILER_READ_H
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
class Read {
|
||||
public:
|
||||
Read():
|
||||
value(0), event(0), eventNext(0)
|
||||
{ }
|
||||
|
||||
virtual bool intersect(SiteMask* mask, unsigned depth = 0) = 0;
|
||||
|
||||
virtual Value* high(Context* c) { abort(c); }
|
||||
|
||||
virtual Value* successor() = 0;
|
||||
|
||||
virtual bool valid() = 0;
|
||||
|
||||
virtual void append(Context* c, Read* r) = 0;
|
||||
|
||||
virtual Read* next(Context* c) = 0;
|
||||
|
||||
Value* value;
|
||||
Event* event;
|
||||
Read* eventNext;
|
||||
};
|
||||
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif // AVIAN_CODEGEN_COMPILER_READ_H
|
301
src/codegen/compiler/regalloc.cpp
Normal file
301
src/codegen/compiler/regalloc.cpp
Normal file
@ -0,0 +1,301 @@
|
||||
/* Copyright (c) 2008-2012, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
#include "target.h"
|
||||
|
||||
#include "codegen/compiler/regalloc.h"
|
||||
#include "codegen/compiler/context.h"
|
||||
#include "codegen/compiler/site.h"
|
||||
#include "codegen/compiler/resource.h"
|
||||
#include "codegen/compiler/read.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
RegisterAllocator::RegisterAllocator(Aborter* a, const RegisterFile* registerFile):
|
||||
a(a),
|
||||
registerFile(registerFile)
|
||||
{ }
|
||||
|
||||
|
||||
bool uniqueSite(Context* c, Value* v, Site* s);
|
||||
unsigned totalFrameSize(Context* c);
|
||||
Read* live(Context* c UNUSED, Value* v);
|
||||
|
||||
unsigned
|
||||
resourceCost(Context* c, Value* v, Resource* r, SiteMask mask,
|
||||
CostCalculator* costCalculator)
|
||||
{
|
||||
if (r->reserved or r->freezeCount or r->referenceCount) {
|
||||
return Target::Impossible;
|
||||
} else {
|
||||
unsigned baseCost =
|
||||
costCalculator ? costCalculator->cost(c, mask) : 0;
|
||||
|
||||
if (r->value) {
|
||||
assert(c, r->value->findSite(r->site));
|
||||
|
||||
if (v and r->value->isBuddyOf(v)) {
|
||||
return baseCost;
|
||||
} else if (uniqueSite(c, r->value, r->site)) {
|
||||
return baseCost + Target::StealUniquePenalty;
|
||||
} else {
|
||||
return baseCost = Target::StealPenalty;
|
||||
}
|
||||
} else {
|
||||
return baseCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
pickRegisterTarget(Context* c, int i, Value* v, uint32_t mask, int* target,
|
||||
unsigned* cost, CostCalculator* costCalculator)
|
||||
{
|
||||
if ((1 << i) & mask) {
|
||||
RegisterResource* r = c->registerResources + i;
|
||||
unsigned myCost = resourceCost
|
||||
(c, v, r, SiteMask(1 << lir::RegisterOperand, 1 << i, NoFrameIndex), costCalculator)
|
||||
+ Target::MinimumRegisterCost;
|
||||
|
||||
if ((static_cast<uint32_t>(1) << i) == mask) {
|
||||
*cost = myCost;
|
||||
return true;
|
||||
} else if (myCost < *cost) {
|
||||
*cost = myCost;
|
||||
*target = i;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
pickRegisterTarget(Context* c, Value* v, uint32_t mask, unsigned* cost,
|
||||
CostCalculator* costCalculator)
|
||||
{
|
||||
int target = lir::NoRegister;
|
||||
*cost = Target::Impossible;
|
||||
|
||||
if (mask & c->regFile->generalRegisters.mask) {
|
||||
for (int i = c->regFile->generalRegisters.limit - 1;
|
||||
i >= c->regFile->generalRegisters.start; --i)
|
||||
{
|
||||
if (pickRegisterTarget(c, i, v, mask, &target, cost, costCalculator)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & c->regFile->floatRegisters.mask) {
|
||||
for (int i = c->regFile->floatRegisters.start;
|
||||
i < static_cast<int>(c->regFile->floatRegisters.limit); ++i)
|
||||
{
|
||||
if (pickRegisterTarget(c, i, v, mask, &target, cost, costCalculator)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
Target
|
||||
pickRegisterTarget(Context* c, Value* v, uint32_t mask,
|
||||
CostCalculator* costCalculator)
|
||||
{
|
||||
unsigned cost;
|
||||
int number = pickRegisterTarget(c, v, mask, &cost, costCalculator);
|
||||
return Target(number, lir::RegisterOperand, cost);
|
||||
}
|
||||
|
||||
unsigned
|
||||
frameCost(Context* c, Value* v, int frameIndex, CostCalculator* costCalculator)
|
||||
{
|
||||
return resourceCost
|
||||
(c, v, c->frameResources + frameIndex, SiteMask(1 << lir::MemoryOperand, 0, frameIndex),
|
||||
costCalculator)
|
||||
+ Target::MinimumFrameCost;
|
||||
}
|
||||
|
||||
Target
|
||||
pickFrameTarget(Context* c, Value* v, CostCalculator* costCalculator)
|
||||
{
|
||||
Target best;
|
||||
|
||||
Value* p = v;
|
||||
do {
|
||||
if (p->home >= 0) {
|
||||
Target mine
|
||||
(p->home, lir::MemoryOperand, frameCost(c, v, p->home, costCalculator));
|
||||
|
||||
if (mine.cost == Target::MinimumFrameCost) {
|
||||
return mine;
|
||||
} else if (mine.cost < best.cost) {
|
||||
best = mine;
|
||||
}
|
||||
}
|
||||
p = p->buddy;
|
||||
} while (p != v);
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
Target
|
||||
pickAnyFrameTarget(Context* c, Value* v, CostCalculator* costCalculator)
|
||||
{
|
||||
Target best;
|
||||
|
||||
unsigned count = totalFrameSize(c);
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
Target mine(i, lir::MemoryOperand, frameCost(c, v, i, costCalculator));
|
||||
if (mine.cost == Target::MinimumFrameCost) {
|
||||
return mine;
|
||||
} else if (mine.cost < best.cost) {
|
||||
best = mine;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
Target
|
||||
pickTarget(Context* c, Value* value, const SiteMask& mask,
|
||||
unsigned registerPenalty, Target best,
|
||||
CostCalculator* costCalculator)
|
||||
{
|
||||
if (mask.typeMask & (1 << lir::RegisterOperand)) {
|
||||
Target mine = pickRegisterTarget
|
||||
(c, value, mask.registerMask, costCalculator);
|
||||
|
||||
mine.cost += registerPenalty;
|
||||
if (mine.cost == Target::MinimumRegisterCost) {
|
||||
return mine;
|
||||
} else if (mine.cost < best.cost) {
|
||||
best = mine;
|
||||
}
|
||||
}
|
||||
|
||||
if (mask.typeMask & (1 << lir::MemoryOperand)) {
|
||||
if (mask.frameIndex >= 0) {
|
||||
Target mine(mask.frameIndex, lir::MemoryOperand,
|
||||
frameCost(c, value, mask.frameIndex, costCalculator));
|
||||
if (mine.cost == Target::MinimumFrameCost) {
|
||||
return mine;
|
||||
} else if (mine.cost < best.cost) {
|
||||
best = mine;
|
||||
}
|
||||
} else if (mask.frameIndex == AnyFrameIndex) {
|
||||
Target mine = pickFrameTarget(c, value, costCalculator);
|
||||
if (mine.cost == Target::MinimumFrameCost) {
|
||||
return mine;
|
||||
} else if (mine.cost < best.cost) {
|
||||
best = mine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
Target
|
||||
pickTarget(Context* c, Read* read, bool intersectRead,
|
||||
unsigned registerReserveCount, CostCalculator* costCalculator)
|
||||
{
|
||||
unsigned registerPenalty
|
||||
= (c->availableGeneralRegisterCount > registerReserveCount
|
||||
? 0 : Target::LowRegisterPenalty);
|
||||
|
||||
Value* value = read->value;
|
||||
|
||||
uint32_t registerMask
|
||||
= (value->type == lir::ValueFloat ? ~0 : c->regFile->generalRegisters.mask);
|
||||
|
||||
SiteMask mask(~0, registerMask, AnyFrameIndex);
|
||||
read->intersect(&mask);
|
||||
|
||||
if (value->type == lir::ValueFloat) {
|
||||
uint32_t floatMask = mask.registerMask & c->regFile->floatRegisters.mask;
|
||||
if (floatMask) {
|
||||
mask.registerMask = floatMask;
|
||||
}
|
||||
}
|
||||
|
||||
Target best;
|
||||
|
||||
Value* successor = read->successor();
|
||||
if (successor) {
|
||||
Read* r = live(c, successor);
|
||||
if (r) {
|
||||
SiteMask intersection = mask;
|
||||
if (r->intersect(&intersection)) {
|
||||
best = pickTarget
|
||||
(c, value, intersection, registerPenalty, best, costCalculator);
|
||||
|
||||
if (best.cost <= Target::MinimumFrameCost) {
|
||||
return best;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
best = pickTarget(c, value, mask, registerPenalty, best, costCalculator);
|
||||
if (best.cost <= Target::MinimumFrameCost) {
|
||||
return best;
|
||||
}
|
||||
|
||||
if (intersectRead) {
|
||||
if (best.cost == Target::Impossible) {
|
||||
fprintf(stderr, "mask type %d reg %d frame %d\n",
|
||||
mask.typeMask, mask.registerMask, mask.frameIndex);
|
||||
abort(c);
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
{ Target mine = pickRegisterTarget(c, value, registerMask, costCalculator);
|
||||
|
||||
mine.cost += registerPenalty;
|
||||
|
||||
if (mine.cost == Target::MinimumRegisterCost) {
|
||||
return mine;
|
||||
} else if (mine.cost < best.cost) {
|
||||
best = mine;
|
||||
}
|
||||
}
|
||||
|
||||
{ Target mine = pickFrameTarget(c, value, costCalculator);
|
||||
if (mine.cost == Target::MinimumFrameCost) {
|
||||
return mine;
|
||||
} else if (mine.cost < best.cost) {
|
||||
best = mine;
|
||||
}
|
||||
}
|
||||
|
||||
if (best.cost >= Target::StealUniquePenalty
|
||||
and c->availableGeneralRegisterCount == 0)
|
||||
{
|
||||
// there are no free registers left, so moving from memory to
|
||||
// memory isn't an option - try harder to find an available frame
|
||||
// site:
|
||||
best = pickAnyFrameTarget(c, value, costCalculator);
|
||||
assert(c, best.cost <= 3);
|
||||
}
|
||||
|
||||
if (best.cost == Target::Impossible) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
} // namespace regalloc
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
106
src/codegen/compiler/regalloc.h
Normal file
106
src/codegen/compiler/regalloc.h
Normal file
@ -0,0 +1,106 @@
|
||||
/* Copyright (c) 2008-2012, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
#ifndef AVIAN_CODEGEN_COMPILER_REGALLOC_H
|
||||
#define AVIAN_CODEGEN_COMPILER_REGALLOC_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "codegen/lir.h"
|
||||
#include "codegen/registers.h"
|
||||
|
||||
class Aborter;
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
class Context;
|
||||
class Value;
|
||||
class SiteMask;
|
||||
class Resource;
|
||||
class Read;
|
||||
|
||||
|
||||
class RegisterAllocator {
|
||||
public:
|
||||
Aborter* a;
|
||||
const RegisterFile* registerFile;
|
||||
|
||||
RegisterAllocator(Aborter* a, const RegisterFile* registerFile);
|
||||
|
||||
};
|
||||
|
||||
class Target {
|
||||
public:
|
||||
static const unsigned MinimumRegisterCost = 0;
|
||||
static const unsigned MinimumFrameCost = 1;
|
||||
static const unsigned StealPenalty = 2;
|
||||
static const unsigned StealUniquePenalty = 4;
|
||||
static const unsigned IndirectMovePenalty = 4;
|
||||
static const unsigned LowRegisterPenalty = 10;
|
||||
static const unsigned Impossible = 20;
|
||||
|
||||
Target(): cost(Impossible) { }
|
||||
|
||||
Target(int index, lir::OperandType type, unsigned cost):
|
||||
index(index), type(type), cost(cost)
|
||||
{ }
|
||||
|
||||
int16_t index;
|
||||
lir::OperandType type;
|
||||
uint8_t cost;
|
||||
};
|
||||
|
||||
class CostCalculator {
|
||||
public:
|
||||
virtual unsigned cost(Context* c, SiteMask mask) = 0;
|
||||
};
|
||||
|
||||
unsigned
|
||||
resourceCost(Context* c, Value* v, Resource* r, SiteMask mask,
|
||||
CostCalculator* costCalculator);
|
||||
|
||||
|
||||
bool
|
||||
pickRegisterTarget(Context* c, int i, Value* v, uint32_t mask, int* target,
|
||||
unsigned* cost, CostCalculator* costCalculator = 0);
|
||||
|
||||
int
|
||||
pickRegisterTarget(Context* c, Value* v, uint32_t mask, unsigned* cost,
|
||||
CostCalculator* costCalculator = 0);
|
||||
|
||||
Target
|
||||
pickRegisterTarget(Context* c, Value* v, uint32_t mask,
|
||||
CostCalculator* costCalculator = 0);
|
||||
|
||||
unsigned
|
||||
frameCost(Context* c, Value* v, int frameIndex, CostCalculator* costCalculator);
|
||||
|
||||
Target
|
||||
pickFrameTarget(Context* c, Value* v, CostCalculator* costCalculator);
|
||||
|
||||
Target
|
||||
pickAnyFrameTarget(Context* c, Value* v, CostCalculator* costCalculator);
|
||||
|
||||
Target
|
||||
pickTarget(Context* c, Value* value, const SiteMask& mask,
|
||||
unsigned registerPenalty, Target best,
|
||||
CostCalculator* costCalculator);
|
||||
|
||||
Target
|
||||
pickTarget(Context* c, Read* read, bool intersectRead,
|
||||
unsigned registerReserveCount, CostCalculator* costCalculator);
|
||||
|
||||
} // namespace regalloc
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif // AVIAN_CODEGEN_COMPILER_REGALLOC_H
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "codegen/compiler/context.h"
|
||||
#include "codegen/compiler/resource.h"
|
||||
#include "codegen/compiler/value.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
@ -17,6 +18,9 @@ namespace compiler {
|
||||
|
||||
const bool DebugResources = false;
|
||||
|
||||
|
||||
void steal(Context* c, Resource* r, Value* thief);
|
||||
|
||||
void decrementAvailableGeneralRegisterCount(Context* c) {
|
||||
assert(c, c->availableGeneralRegisterCount);
|
||||
-- c->availableGeneralRegisterCount;
|
||||
@ -155,6 +159,68 @@ unsigned FrameResource::index(Context* c) {
|
||||
}
|
||||
|
||||
|
||||
void acquire(Context* c, Resource* resource, Value* value, Site* site) {
|
||||
assert(c, value);
|
||||
assert(c, site);
|
||||
|
||||
if (not resource->reserved) {
|
||||
if (DebugResources) {
|
||||
char buffer[256]; resource->toString(c, buffer, 256);
|
||||
fprintf(stderr, "%p acquire %s\n", value, buffer);
|
||||
}
|
||||
|
||||
if (resource->value) {
|
||||
assert(c, resource->value->findSite(resource->site));
|
||||
assert(c, not value->findSite(resource->site));
|
||||
|
||||
steal(c, resource, value);
|
||||
}
|
||||
|
||||
if (c->acquiredResources) {
|
||||
c->acquiredResources->previousAcquired = resource;
|
||||
resource->nextAcquired = c->acquiredResources;
|
||||
}
|
||||
c->acquiredResources = resource;
|
||||
|
||||
resource->value = value;
|
||||
resource->site = site;
|
||||
}
|
||||
}
|
||||
|
||||
void release(Context* c, Resource* resource, Value* value UNUSED, Site* site UNUSED) {
|
||||
if (not resource->reserved) {
|
||||
if (DebugResources) {
|
||||
char buffer[256]; resource->toString(c, buffer, 256);
|
||||
fprintf(stderr, "%p release %s\n", resource->value, buffer);
|
||||
}
|
||||
|
||||
assert(c, resource->value);
|
||||
assert(c, resource->site);
|
||||
|
||||
assert(c, resource->value->isBuddyOf(value));
|
||||
assert(c, site == resource->site);
|
||||
|
||||
Resource* next = resource->nextAcquired;
|
||||
if (next) {
|
||||
next->previousAcquired = resource->previousAcquired;
|
||||
resource->nextAcquired = 0;
|
||||
}
|
||||
|
||||
Resource* previous = resource->previousAcquired;
|
||||
if (previous) {
|
||||
previous->nextAcquired = next;
|
||||
resource->previousAcquired = 0;
|
||||
} else {
|
||||
assert(c, c->acquiredResources == resource);
|
||||
c->acquiredResources = next;
|
||||
}
|
||||
|
||||
resource->value = 0;
|
||||
resource->site = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
@ -66,6 +66,10 @@ class FrameResource: public Resource {
|
||||
virtual unsigned index(Context*);
|
||||
};
|
||||
|
||||
void acquire(Context* c, Resource* resource, Value* value, Site* site);
|
||||
|
||||
void release(Context* c, Resource* resource, Value* value, Site* site);
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "codegen/compiler/context.h"
|
||||
#include "codegen/compiler/value.h"
|
||||
#include "codegen/compiler/site.h"
|
||||
#include "codegen/compiler/resource.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
@ -97,6 +98,278 @@ Site* constantSite(Context* c, int64_t value) {
|
||||
return constantSite(c, resolved(c, value));
|
||||
}
|
||||
|
||||
|
||||
|
||||
class AddressSite: public Site {
|
||||
public:
|
||||
AddressSite(Promise* address): address(address) { }
|
||||
|
||||
virtual unsigned toString(Context*, char* buffer, unsigned bufferSize) {
|
||||
if (address->resolved()) {
|
||||
return vm::snprintf
|
||||
(buffer, bufferSize, "address %" LLD, address->value());
|
||||
} else {
|
||||
return vm::snprintf(buffer, bufferSize, "address unresolved");
|
||||
}
|
||||
}
|
||||
|
||||
virtual unsigned copyCost(Context*, Site* s) {
|
||||
return (s == this ? 0 : AddressCopyCost);
|
||||
}
|
||||
|
||||
virtual bool match(Context*, const SiteMask& mask) {
|
||||
return mask.typeMask & (1 << lir::AddressOperand);
|
||||
}
|
||||
|
||||
virtual bool loneMatch(Context*, const SiteMask&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool matchNextWord(Context* c, Site*, unsigned) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
virtual lir::OperandType type(Context*) {
|
||||
return lir::AddressOperand;
|
||||
}
|
||||
|
||||
virtual void asAssemblerOperand(Context* c UNUSED, Site* high UNUSED,
|
||||
lir::Operand* result)
|
||||
{
|
||||
assert(c, high == this);
|
||||
|
||||
new (result) lir::Address(address);
|
||||
}
|
||||
|
||||
virtual Site* copy(Context* c) {
|
||||
return addressSite(c, address);
|
||||
}
|
||||
|
||||
virtual Site* copyLow(Context* c) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
virtual Site* copyHigh(Context* c) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
virtual Site* makeNextWord(Context* c, unsigned) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
virtual SiteMask mask(Context*) {
|
||||
return SiteMask(1 << lir::AddressOperand, 0, NoFrameIndex);
|
||||
}
|
||||
|
||||
virtual SiteMask nextWordMask(Context* c, unsigned) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
Promise* address;
|
||||
};
|
||||
|
||||
Site* addressSite(Context* c, Promise* address) {
|
||||
return new(c->zone) AddressSite(address);
|
||||
}
|
||||
|
||||
|
||||
RegisterSite::RegisterSite(uint32_t mask, int number):
|
||||
mask_(mask), number(number)
|
||||
{ }
|
||||
|
||||
unsigned RegisterSite::toString(Context*, char* buffer, unsigned bufferSize) {
|
||||
if (number != lir::NoRegister) {
|
||||
return vm::snprintf(buffer, bufferSize, "%p register %d", this, number);
|
||||
} else {
|
||||
return vm::snprintf(buffer, bufferSize,
|
||||
"%p register unacquired (mask %d)", this, mask_);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned RegisterSite::copyCost(Context* c, Site* s) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
if (s and
|
||||
(this == s or
|
||||
(s->type(c) == lir::RegisterOperand
|
||||
and (static_cast<RegisterSite*>(s)->mask_ & (1 << number)))))
|
||||
{
|
||||
return 0;
|
||||
} else {
|
||||
return RegisterCopyCost;
|
||||
}
|
||||
}
|
||||
|
||||
bool RegisterSite::match(Context* c UNUSED, const SiteMask& mask) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
if ((mask.typeMask & (1 << lir::RegisterOperand))) {
|
||||
return ((static_cast<uint64_t>(1) << number) & mask.registerMask);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool RegisterSite::loneMatch(Context* c UNUSED, const SiteMask& mask) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
if ((mask.typeMask & (1 << lir::RegisterOperand))) {
|
||||
return ((static_cast<uint64_t>(1) << number) == mask.registerMask);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool RegisterSite::matchNextWord(Context* c, Site* s, unsigned) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
if (s->type(c) != lir::RegisterOperand) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RegisterSite* rs = static_cast<RegisterSite*>(s);
|
||||
unsigned size = rs->registerSize(c);
|
||||
if (size > vm::TargetBytesPerWord) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
return number == rs->number;
|
||||
} else {
|
||||
uint32_t mask = c->regFile->generalRegisters.mask;
|
||||
return ((1 << number) & mask) and ((1 << rs->number) & mask);
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterSite::acquire(Context* c, Value* v) {
|
||||
Target target;
|
||||
if (number != lir::NoRegister) {
|
||||
target = Target(number, lir::RegisterOperand, 0);
|
||||
} else {
|
||||
target = pickRegisterTarget(c, v, mask_);
|
||||
expect(c, target.cost < Target::Impossible);
|
||||
}
|
||||
|
||||
RegisterResource* resource = c->registerResources + target.index;
|
||||
compiler::acquire(c, resource, v, this);
|
||||
|
||||
number = target.index;
|
||||
}
|
||||
|
||||
void RegisterSite::release(Context* c, Value* v) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
compiler::release(c, c->registerResources + number, v, this);
|
||||
}
|
||||
|
||||
void RegisterSite::freeze(Context* c, Value* v) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
c->registerResources[number].freeze(c, v);
|
||||
}
|
||||
|
||||
void RegisterSite::thaw(Context* c, Value* v) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
c->registerResources[number].thaw(c, v);
|
||||
}
|
||||
|
||||
bool RegisterSite::frozen(Context* c UNUSED) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
return c->registerResources[number].freezeCount != 0;
|
||||
}
|
||||
|
||||
lir::OperandType RegisterSite::type(Context*) {
|
||||
return lir::RegisterOperand;
|
||||
}
|
||||
|
||||
void RegisterSite::asAssemblerOperand(Context* c UNUSED, Site* high,
|
||||
lir::Operand* result)
|
||||
{
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
int highNumber;
|
||||
if (high != this) {
|
||||
highNumber = static_cast<RegisterSite*>(high)->number;
|
||||
assert(c, highNumber != lir::NoRegister);
|
||||
} else {
|
||||
highNumber = lir::NoRegister;
|
||||
}
|
||||
|
||||
new (result) lir::Register(number, highNumber);
|
||||
}
|
||||
|
||||
Site* RegisterSite::copy(Context* c) {
|
||||
uint32_t mask;
|
||||
|
||||
if (number != lir::NoRegister) {
|
||||
mask = 1 << number;
|
||||
} else {
|
||||
mask = mask_;
|
||||
}
|
||||
|
||||
return freeRegisterSite(c, mask);
|
||||
}
|
||||
|
||||
Site* RegisterSite::copyLow(Context* c) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
Site* RegisterSite::copyHigh(Context* c) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
Site* RegisterSite::makeNextWord(Context* c, unsigned) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
assert(c, ((1 << number) & c->regFile->generalRegisters.mask));
|
||||
|
||||
return freeRegisterSite(c, c->regFile->generalRegisters.mask);
|
||||
}
|
||||
|
||||
SiteMask RegisterSite::mask(Context* c UNUSED) {
|
||||
return SiteMask(1 << lir::RegisterOperand, mask_, NoFrameIndex);
|
||||
}
|
||||
|
||||
SiteMask RegisterSite::nextWordMask(Context* c, unsigned) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
if (registerSize(c) > vm::TargetBytesPerWord) {
|
||||
return SiteMask
|
||||
(1 << lir::RegisterOperand, number, NoFrameIndex);
|
||||
} else {
|
||||
return SiteMask
|
||||
(1 << lir::RegisterOperand, c->regFile->generalRegisters.mask, NoFrameIndex);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned RegisterSite::registerSize(Context* c) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
if ((1 << number) & c->regFile->floatRegisters.mask) {
|
||||
return c->arch->floatRegisterSize();
|
||||
} else {
|
||||
return vm::TargetBytesPerWord;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned RegisterSite::registerMask(Context* c UNUSED) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
return 1 << number;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Site* registerSite(Context* c, int number) {
|
||||
assert(c, number >= 0);
|
||||
assert(c, (1 << number) & (c->regFile->generalRegisters.mask
|
||||
| c->regFile->floatRegisters.mask));
|
||||
|
||||
return new(c->zone) RegisterSite(1 << number, number);
|
||||
}
|
||||
|
||||
Site* freeRegisterSite(Context* c, uint32_t mask) {
|
||||
return new(c->zone) RegisterSite(mask, lir::NoRegister);
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
@ -11,6 +11,9 @@
|
||||
#ifndef AVIAN_CODEGEN_COMPILER_SITE_H
|
||||
#define AVIAN_CODEGEN_COMPILER_SITE_H
|
||||
|
||||
#include "codegen/compiler/value.h"
|
||||
#include "codegen/compiler/context.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
@ -183,6 +186,60 @@ class ConstantSite: public Site {
|
||||
Promise* value;
|
||||
};
|
||||
|
||||
Site* addressSite(Context* c, Promise* address);
|
||||
|
||||
class RegisterSite: public Site {
|
||||
public:
|
||||
RegisterSite(uint32_t mask, int number);
|
||||
|
||||
virtual unsigned toString(Context*, char* buffer, unsigned bufferSize);
|
||||
|
||||
virtual unsigned copyCost(Context* c, Site* s);
|
||||
|
||||
virtual bool match(Context* c UNUSED, const SiteMask& mask);
|
||||
|
||||
virtual bool loneMatch(Context* c UNUSED, const SiteMask& mask);
|
||||
|
||||
virtual bool matchNextWord(Context* c, Site* s, unsigned);
|
||||
|
||||
virtual void acquire(Context* c, Value* v);
|
||||
|
||||
virtual void release(Context* c, Value* v);
|
||||
|
||||
virtual void freeze(Context* c, Value* v);
|
||||
|
||||
virtual void thaw(Context* c, Value* v);
|
||||
|
||||
virtual bool frozen(Context* c UNUSED);
|
||||
|
||||
virtual lir::OperandType type(Context*);
|
||||
|
||||
virtual void asAssemblerOperand(Context* c UNUSED, Site* high,
|
||||
lir::Operand* result);
|
||||
|
||||
virtual Site* copy(Context* c);
|
||||
|
||||
virtual Site* copyLow(Context* c);
|
||||
|
||||
virtual Site* copyHigh(Context* c);
|
||||
|
||||
virtual Site* makeNextWord(Context* c, unsigned);
|
||||
|
||||
virtual SiteMask mask(Context* c UNUSED);
|
||||
|
||||
virtual SiteMask nextWordMask(Context* c, unsigned);
|
||||
|
||||
virtual unsigned registerSize(Context* c);
|
||||
|
||||
virtual unsigned registerMask(Context* c UNUSED);
|
||||
|
||||
uint32_t mask_;
|
||||
int number;
|
||||
};
|
||||
|
||||
Site* registerSite(Context* c, int number);
|
||||
Site* freeRegisterSite(Context* c, uint32_t mask);
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
43
src/codegen/compiler/value.cpp
Normal file
43
src/codegen/compiler/value.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
/* Copyright (c) 2008-2012, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
#include "target.h"
|
||||
|
||||
#include "codegen/compiler/regalloc.h"
|
||||
#include "codegen/compiler/site.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
Value::Value(Site* site, Site* target, lir::ValueType type):
|
||||
reads(0), lastRead(0), sites(site), source(0), target(target), buddy(this),
|
||||
nextWord(this), home(NoFrameIndex), type(type), wordIndex(0)
|
||||
{ }
|
||||
|
||||
bool Value::findSite(Site* site) {
|
||||
for (Site* s = this->sites; s; s = s->next) {
|
||||
if (s == site) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Value::isBuddyOf(Value* b) {
|
||||
Value* a = this;
|
||||
if (a == b) return true;
|
||||
for (Value* p = a->buddy; p != a; p = p->buddy) {
|
||||
if (p == b) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace regalloc
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
@ -13,6 +13,8 @@
|
||||
|
||||
#include "codegen/lir.h"
|
||||
|
||||
#include "codegen/compiler.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
@ -25,11 +27,6 @@ const int NoFrameIndex = -1;
|
||||
|
||||
class Value: public Compiler::Operand {
|
||||
public:
|
||||
Value(Site* site, Site* target, lir::ValueType type):
|
||||
reads(0), lastRead(0), sites(site), source(0), target(target), buddy(this),
|
||||
nextWord(this), home(NoFrameIndex), type(type), wordIndex(0)
|
||||
{ }
|
||||
|
||||
Read* reads;
|
||||
Read* lastRead;
|
||||
Site* sites;
|
||||
@ -40,6 +37,12 @@ class Value: public Compiler::Operand {
|
||||
int16_t home;
|
||||
lir::ValueType type;
|
||||
uint8_t wordIndex;
|
||||
|
||||
Value(Site* site, Site* target, lir::ValueType type);
|
||||
|
||||
bool findSite(Site* site);
|
||||
|
||||
bool isBuddyOf(Value* b);
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
|
@ -1,24 +0,0 @@
|
||||
/* Copyright (c) 2008-2012, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
#include "codegen/regalloc.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace regalloc {
|
||||
|
||||
RegisterAllocator::RegisterAllocator(Aborter* a, const RegisterFile* registerFile):
|
||||
a(a),
|
||||
registerFile(registerFile)
|
||||
{ }
|
||||
|
||||
} // namespace regalloc
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
@ -1,37 +0,0 @@
|
||||
/* Copyright (c) 2008-2012, Avian Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software
|
||||
for any purpose with or without fee is hereby granted, provided
|
||||
that the above copyright notice and this permission notice appear
|
||||
in all copies.
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
#ifndef AVIAN_CODEGEN_REGALLOC_H
|
||||
#define AVIAN_CODEGEN_REGALLOC_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "codegen/registers.h"
|
||||
|
||||
class Aborter;
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace regalloc {
|
||||
|
||||
class RegisterAllocator {
|
||||
public:
|
||||
Aborter* a;
|
||||
const RegisterFile* registerFile;
|
||||
|
||||
RegisterAllocator(Aborter* a, const RegisterFile* registerFile);
|
||||
|
||||
};
|
||||
|
||||
} // namespace regalloc
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif // AVIAN_CODEGEN_REGALLOC_H
|
Loading…
Reference in New Issue
Block a user