mirror of
https://github.com/corda/corda.git
synced 2025-01-06 05:04:20 +00:00
Merge remote-tracking branch 'joshuawarner32/master'
This commit is contained in:
commit
66108032a6
13
makefile
13
makefile
@ -923,7 +923,7 @@ generated-code = \
|
||||
$(build)/type-name-initializations.cpp \
|
||||
$(build)/type-maps.cpp
|
||||
|
||||
vm-depends := $(generated-code) $(wildcard $(src)/*.h) $(wildcard $(src)/codegen/*.h)
|
||||
vm-depends := $(generated-code) $(wildcard $(src)/*.h) $(wildcard $(src)/codegen/*.h) $(wildcard $(src)/codegen/compiler/*.h)
|
||||
|
||||
vm-sources = \
|
||||
$(src)/$(system).cpp \
|
||||
@ -953,6 +953,17 @@ embed-objects = $(call cpp-objects,$(embed-sources),$(src),$(build-embed))
|
||||
ifeq ($(process),compile)
|
||||
vm-sources += \
|
||||
$(src)/codegen/compiler.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/compiler/read.cpp \
|
||||
$(src)/codegen/compiler/event.cpp \
|
||||
$(src)/codegen/compiler/promise.cpp \
|
||||
$(src)/codegen/compiler/frame.cpp \
|
||||
$(src)/codegen/compiler/ir.cpp \
|
||||
$(src)/codegen/registers.cpp \
|
||||
$(src)/codegen/targets.cpp
|
||||
|
||||
ifeq ($(codegen-targets),native)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,13 +8,32 @@
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
#ifndef ASSEMBLER_H
|
||||
#define ASSEMBLER_H
|
||||
#ifndef AVIAN_CODEGEN_ASSEMBLER_H
|
||||
#define AVIAN_CODEGEN_ASSEMBLER_H
|
||||
|
||||
#include "system.h"
|
||||
#include "zone.h"
|
||||
|
||||
namespace vm {
|
||||
#include "codegen/lir.h"
|
||||
#include "codegen/promise.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
|
||||
class RegisterFile;
|
||||
|
||||
class OperandInfo {
|
||||
public:
|
||||
const unsigned size;
|
||||
const lir::OperandType type;
|
||||
lir::Operand* const operand;
|
||||
|
||||
inline OperandInfo(unsigned size, lir::OperandType type, lir::Operand* operand):
|
||||
size(size),
|
||||
type(type),
|
||||
operand(operand)
|
||||
{ }
|
||||
};
|
||||
|
||||
#ifdef AVIAN_TAILS
|
||||
const bool TailCalls = true;
|
||||
@ -28,286 +47,8 @@ const bool UseFramePointer = true;
|
||||
const bool UseFramePointer = false;
|
||||
#endif
|
||||
|
||||
enum Operation {
|
||||
Return,
|
||||
LoadBarrier,
|
||||
StoreStoreBarrier,
|
||||
StoreLoadBarrier,
|
||||
Trap
|
||||
};
|
||||
|
||||
const unsigned OperationCount = Trap + 1;
|
||||
|
||||
enum UnaryOperation {
|
||||
Call,
|
||||
LongCall,
|
||||
AlignedLongCall,
|
||||
AlignedCall,
|
||||
Jump,
|
||||
LongJump,
|
||||
AlignedLongJump,
|
||||
AlignedJump,
|
||||
|
||||
NoUnaryOperation = -1
|
||||
};
|
||||
|
||||
const unsigned UnaryOperationCount = AlignedJump + 1;
|
||||
|
||||
enum BinaryOperation {
|
||||
Move,
|
||||
MoveLow,
|
||||
MoveHigh,
|
||||
MoveZ,
|
||||
Negate,
|
||||
FloatNegate,
|
||||
Float2Float,
|
||||
Float2Int,
|
||||
Int2Float,
|
||||
FloatSquareRoot,
|
||||
FloatAbsolute,
|
||||
Absolute,
|
||||
|
||||
NoBinaryOperation = -1
|
||||
};
|
||||
|
||||
const unsigned BinaryOperationCount = Absolute + 1;
|
||||
|
||||
enum TernaryOperation {
|
||||
Add,
|
||||
Subtract,
|
||||
Multiply,
|
||||
Divide,
|
||||
Remainder,
|
||||
ShiftLeft,
|
||||
ShiftRight,
|
||||
UnsignedShiftRight,
|
||||
And,
|
||||
Or,
|
||||
Xor,
|
||||
FloatAdd,
|
||||
FloatSubtract,
|
||||
FloatMultiply,
|
||||
FloatDivide,
|
||||
FloatRemainder,
|
||||
FloatMax,
|
||||
FloatMin,
|
||||
JumpIfLess,
|
||||
JumpIfGreater,
|
||||
JumpIfLessOrEqual,
|
||||
JumpIfGreaterOrEqual,
|
||||
JumpIfEqual,
|
||||
JumpIfNotEqual,
|
||||
JumpIfFloatEqual,
|
||||
JumpIfFloatNotEqual,
|
||||
JumpIfFloatLess,
|
||||
JumpIfFloatGreater,
|
||||
JumpIfFloatLessOrEqual,
|
||||
JumpIfFloatGreaterOrEqual,
|
||||
JumpIfFloatLessOrUnordered,
|
||||
JumpIfFloatGreaterOrUnordered,
|
||||
JumpIfFloatLessOrEqualOrUnordered,
|
||||
JumpIfFloatGreaterOrEqualOrUnordered,
|
||||
|
||||
NoTernaryOperation = -1
|
||||
};
|
||||
|
||||
const unsigned TernaryOperationCount
|
||||
= JumpIfFloatGreaterOrEqualOrUnordered + 1;
|
||||
|
||||
const unsigned NonBranchTernaryOperationCount = FloatMin + 1;
|
||||
const unsigned BranchOperationCount
|
||||
= JumpIfFloatGreaterOrEqualOrUnordered - FloatMin;
|
||||
|
||||
enum OperandType {
|
||||
ConstantOperand,
|
||||
AddressOperand,
|
||||
RegisterOperand,
|
||||
MemoryOperand
|
||||
};
|
||||
|
||||
enum ValueType {
|
||||
ValueGeneral,
|
||||
ValueFloat
|
||||
};
|
||||
|
||||
const unsigned OperandTypeCount = MemoryOperand + 1;
|
||||
|
||||
const int NoRegister = -1;
|
||||
|
||||
class Promise {
|
||||
public:
|
||||
class Listener {
|
||||
public:
|
||||
virtual bool resolve(int64_t value, void** location) = 0;
|
||||
|
||||
Listener* next;
|
||||
};
|
||||
|
||||
virtual int64_t value() = 0;
|
||||
virtual bool resolved() = 0;
|
||||
virtual Listener* listen(unsigned) { return 0; }
|
||||
};
|
||||
|
||||
class ResolvedPromise: public Promise {
|
||||
public:
|
||||
ResolvedPromise(int64_t value): value_(value) { }
|
||||
|
||||
virtual int64_t value() {
|
||||
return value_;
|
||||
}
|
||||
|
||||
virtual bool resolved() {
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t value_;
|
||||
};
|
||||
|
||||
class ShiftMaskPromise: public Promise {
|
||||
public:
|
||||
ShiftMaskPromise(Promise* base, unsigned shift, int64_t mask):
|
||||
base(base), shift(shift), mask(mask)
|
||||
{ }
|
||||
|
||||
virtual int64_t value() {
|
||||
return (base->value() >> shift) & mask;
|
||||
}
|
||||
|
||||
virtual bool resolved() {
|
||||
return base->resolved();
|
||||
}
|
||||
|
||||
Promise* base;
|
||||
unsigned shift;
|
||||
int64_t mask;
|
||||
};
|
||||
|
||||
class CombinedPromise: public Promise {
|
||||
public:
|
||||
CombinedPromise(Promise* low, Promise* high):
|
||||
low(low), high(high)
|
||||
{ }
|
||||
|
||||
virtual int64_t value() {
|
||||
return low->value() | (high->value() << 32);
|
||||
}
|
||||
|
||||
virtual bool resolved() {
|
||||
return low->resolved() and high->resolved();
|
||||
}
|
||||
|
||||
Promise* low;
|
||||
Promise* high;
|
||||
};
|
||||
|
||||
class OffsetPromise: public Promise {
|
||||
public:
|
||||
OffsetPromise(Promise* base, int64_t offset):
|
||||
base(base), offset(offset)
|
||||
{ }
|
||||
|
||||
virtual int64_t value() {
|
||||
return base->value() + offset;
|
||||
}
|
||||
|
||||
virtual bool resolved() {
|
||||
return base->resolved();
|
||||
}
|
||||
|
||||
Promise* base;
|
||||
int64_t offset;
|
||||
};
|
||||
|
||||
class ListenPromise: public Promise {
|
||||
public:
|
||||
ListenPromise(System* s, Allocator* allocator):
|
||||
s(s), allocator(allocator), listener(0)
|
||||
{ }
|
||||
|
||||
virtual int64_t value() {
|
||||
abort(s);
|
||||
}
|
||||
|
||||
virtual bool resolved() {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual Listener* listen(unsigned sizeInBytes) {
|
||||
Listener* l = static_cast<Listener*>(allocator->allocate(sizeInBytes));
|
||||
l->next = listener;
|
||||
listener = l;
|
||||
return l;
|
||||
}
|
||||
|
||||
System* s;
|
||||
Allocator* allocator;
|
||||
Listener* listener;
|
||||
Promise* promise;
|
||||
};
|
||||
|
||||
class DelayedPromise: public ListenPromise {
|
||||
public:
|
||||
DelayedPromise(System* s, Allocator* allocator, Promise* basis,
|
||||
DelayedPromise* next):
|
||||
ListenPromise(s, allocator), basis(basis), next(next)
|
||||
{ }
|
||||
|
||||
virtual int64_t value() {
|
||||
abort(s);
|
||||
}
|
||||
|
||||
virtual bool resolved() {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual Listener* listen(unsigned sizeInBytes) {
|
||||
Listener* l = static_cast<Listener*>(allocator->allocate(sizeInBytes));
|
||||
l->next = listener;
|
||||
listener = l;
|
||||
return l;
|
||||
}
|
||||
|
||||
Promise* basis;
|
||||
DelayedPromise* next;
|
||||
};
|
||||
|
||||
class Assembler {
|
||||
public:
|
||||
class Operand { };
|
||||
|
||||
class Constant: public Operand {
|
||||
public:
|
||||
Constant(Promise* value): value(value) { }
|
||||
|
||||
Promise* value;
|
||||
};
|
||||
|
||||
class Address: public Operand {
|
||||
public:
|
||||
Address(Promise* address): address(address) { }
|
||||
|
||||
Promise* address;
|
||||
};
|
||||
|
||||
class Register: public Operand {
|
||||
public:
|
||||
Register(int low, int high = NoRegister): low(low), high(high) { }
|
||||
|
||||
int low;
|
||||
int high;
|
||||
};
|
||||
|
||||
class Memory: public Operand {
|
||||
public:
|
||||
Memory(int base, int offset, int index = NoRegister, unsigned scale = 1):
|
||||
base(base), offset(offset), index(index), scale(scale)
|
||||
{ }
|
||||
|
||||
int base;
|
||||
int offset;
|
||||
int index;
|
||||
unsigned scale;
|
||||
};
|
||||
|
||||
class Client {
|
||||
public:
|
||||
@ -327,8 +68,7 @@ class Assembler {
|
||||
public:
|
||||
virtual unsigned floatRegisterSize() = 0;
|
||||
|
||||
virtual uint32_t generalRegisterMask() = 0;
|
||||
virtual uint32_t floatRegisterMask() = 0;
|
||||
virtual const RegisterFile* registerFile() = 0;
|
||||
|
||||
virtual int scratch() = 0;
|
||||
virtual int stack() = 0;
|
||||
@ -342,8 +82,8 @@ class Assembler {
|
||||
|
||||
virtual uintptr_t maximumImmediateJump() = 0;
|
||||
|
||||
virtual bool alwaysCondensed(BinaryOperation op) = 0;
|
||||
virtual bool alwaysCondensed(TernaryOperation op) = 0;
|
||||
virtual bool alwaysCondensed(lir::BinaryOperation op) = 0;
|
||||
virtual bool alwaysCondensed(lir::TernaryOperation op) = 0;
|
||||
|
||||
virtual bool reserved(int register_) = 0;
|
||||
|
||||
@ -360,7 +100,7 @@ class Assembler {
|
||||
|
||||
virtual bool matchCall(void* returnAddress, void* target) = 0;
|
||||
|
||||
virtual void updateCall(UnaryOperation op, void* returnAddress,
|
||||
virtual void updateCall(lir::UnaryOperation op, void* returnAddress,
|
||||
void* newTarget) = 0;
|
||||
|
||||
virtual void setConstant(void* dst, uint64_t constant) = 0;
|
||||
@ -379,17 +119,17 @@ class Assembler {
|
||||
virtual int framePointerOffset() = 0;
|
||||
|
||||
virtual void plan
|
||||
(UnaryOperation op,
|
||||
(lir::UnaryOperation op,
|
||||
unsigned aSize, uint8_t* aTypeMask, uint64_t* aRegisterMask,
|
||||
bool* thunk) = 0;
|
||||
|
||||
virtual void planSource
|
||||
(BinaryOperation op,
|
||||
(lir::BinaryOperation op,
|
||||
unsigned aSize, uint8_t* aTypeMask, uint64_t* aRegisterMask,
|
||||
unsigned bSize, bool* thunk) = 0;
|
||||
|
||||
virtual void planDestination
|
||||
(BinaryOperation op,
|
||||
(lir::BinaryOperation op,
|
||||
unsigned aSize, uint8_t aTypeMask, uint64_t aRegisterMask,
|
||||
unsigned bSize, uint8_t* bTypeMask, uint64_t* bRegisterMask) = 0;
|
||||
|
||||
@ -399,18 +139,18 @@ class Assembler {
|
||||
uint8_t dstTypeMask, uint64_t dstRegisterMask) = 0;
|
||||
|
||||
virtual void planSource
|
||||
(TernaryOperation op,
|
||||
(lir::TernaryOperation op,
|
||||
unsigned aSize, uint8_t* aTypeMask, uint64_t* aRegisterMask,
|
||||
unsigned bSize, uint8_t* bTypeMask, uint64_t* bRegisterMask,
|
||||
unsigned cSize, bool* thunk) = 0;
|
||||
|
||||
virtual void planDestination
|
||||
(TernaryOperation op,
|
||||
(lir::TernaryOperation op,
|
||||
unsigned aSize, uint8_t aTypeMask, uint64_t aRegisterMask,
|
||||
unsigned bSize, uint8_t bTypeMask, uint64_t bRegisterMask,
|
||||
unsigned cSize, uint8_t* cTypeMask, uint64_t* cRegisterMask) = 0;
|
||||
|
||||
virtual Assembler* makeAssembler(Allocator*, Zone*) = 0;
|
||||
virtual Assembler* makeAssembler(vm::Allocator*, vm::Zone*) = 0;
|
||||
|
||||
virtual void acquire() = 0;
|
||||
virtual void release() = 0;
|
||||
@ -437,19 +177,10 @@ class Assembler {
|
||||
unsigned stackOffsetFromThread)
|
||||
= 0;
|
||||
|
||||
virtual void apply(Operation op) = 0;
|
||||
|
||||
virtual void apply(UnaryOperation op,
|
||||
unsigned aSize, OperandType aType, Operand* aOperand) = 0;
|
||||
|
||||
virtual void apply(BinaryOperation op,
|
||||
unsigned aSize, OperandType aType, Operand* aOperand,
|
||||
unsigned bSize, OperandType bType, Operand* bOperand) = 0;
|
||||
|
||||
virtual void apply(TernaryOperation op,
|
||||
unsigned aSize, OperandType aType, Operand* aOperand,
|
||||
unsigned bSize, OperandType bType, Operand* bOperand,
|
||||
unsigned cSize, OperandType cType, Operand* cOperand) = 0;
|
||||
virtual void apply(lir::Operation op) = 0;
|
||||
virtual void apply(lir::UnaryOperation op, OperandInfo a) = 0;
|
||||
virtual void apply(lir::BinaryOperation op, OperandInfo a, OperandInfo b) = 0;
|
||||
virtual void apply(lir::TernaryOperation op, OperandInfo a, OperandInfo b, OperandInfo c) = 0;
|
||||
|
||||
virtual void setDestination(uint8_t* dst) = 0;
|
||||
|
||||
@ -468,6 +199,7 @@ class Assembler {
|
||||
virtual void dispose() = 0;
|
||||
};
|
||||
|
||||
} // namespace vm
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif//ASSEMBLER_H
|
||||
#endif // AVIAN_CODEGEN_ASSEMBLER_H
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,14 +8,15 @@
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
#ifndef COMPILER_H
|
||||
#define COMPILER_H
|
||||
#ifndef AVIAN_CODEGEN_COMPILER_H
|
||||
#define AVIAN_CODEGEN_COMPILER_H
|
||||
|
||||
#include "system.h"
|
||||
#include "zone.h"
|
||||
#include "assembler.h"
|
||||
|
||||
namespace vm {
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
|
||||
class TraceHandler {
|
||||
public:
|
||||
@ -26,10 +27,10 @@ class Compiler {
|
||||
public:
|
||||
class Client {
|
||||
public:
|
||||
virtual intptr_t getThunk(UnaryOperation op, unsigned size) = 0;
|
||||
virtual intptr_t getThunk(BinaryOperation op, unsigned size,
|
||||
virtual intptr_t getThunk(lir::UnaryOperation op, unsigned size) = 0;
|
||||
virtual intptr_t getThunk(lir::BinaryOperation op, unsigned size,
|
||||
unsigned resultSize) = 0;
|
||||
virtual intptr_t getThunk(TernaryOperation op, unsigned size,
|
||||
virtual intptr_t getThunk(lir::TernaryOperation op, unsigned size,
|
||||
unsigned resultSize, bool* threadParameter) = 0;
|
||||
};
|
||||
|
||||
@ -200,9 +201,10 @@ class Compiler {
|
||||
};
|
||||
|
||||
Compiler*
|
||||
makeCompiler(System* system, Assembler* assembler, Zone* zone,
|
||||
makeCompiler(vm::System* system, Assembler* assembler, vm::Zone* zone,
|
||||
Compiler::Client* client);
|
||||
|
||||
} // namespace vm
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif//COMPILER_H
|
||||
#endif // AVIAN_CODEGEN_COMPILER_H
|
||||
|
68
src/codegen/compiler/context.cpp
Normal file
68
src/codegen/compiler/context.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
/* 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/compiler/context.h"
|
||||
#include "codegen/compiler/resource.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
Context::Context(vm::System* system, Assembler* assembler, vm::Zone* zone,
|
||||
Compiler::Client* client):
|
||||
system(system),
|
||||
assembler(assembler),
|
||||
arch(assembler->arch()),
|
||||
zone(zone),
|
||||
client(client),
|
||||
stack(0),
|
||||
locals(0),
|
||||
saved(0),
|
||||
predecessor(0),
|
||||
logicalCode(0),
|
||||
regFile(arch->registerFile()),
|
||||
regAlloc(system, arch->registerFile()),
|
||||
registerResources
|
||||
(static_cast<RegisterResource*>
|
||||
(zone->allocate(sizeof(RegisterResource) * regFile->allRegisters.limit))),
|
||||
frameResources(0),
|
||||
acquiredResources(0),
|
||||
firstConstant(0),
|
||||
lastConstant(0),
|
||||
machineCode(0),
|
||||
firstEvent(0),
|
||||
lastEvent(0),
|
||||
forkState(0),
|
||||
subroutine(0),
|
||||
firstBlock(0),
|
||||
logicalIp(-1),
|
||||
constantCount(0),
|
||||
logicalCodeLength(0),
|
||||
parameterFootprint(0),
|
||||
localFootprint(0),
|
||||
machineCodeSize(0),
|
||||
alignedFrameSize(0),
|
||||
availableGeneralRegisterCount(regFile->generalRegisters.limit - regFile->generalRegisters.start)
|
||||
{
|
||||
for (unsigned i = regFile->generalRegisters.start; i < regFile->generalRegisters.limit; ++i) {
|
||||
new (registerResources + i) RegisterResource(arch->reserved(i));
|
||||
|
||||
if (registerResources[i].reserved) {
|
||||
-- availableGeneralRegisterCount;
|
||||
}
|
||||
}
|
||||
for (unsigned i = regFile->floatRegisters.start; i < regFile->floatRegisters.limit; ++i) {
|
||||
new (registerResources + i) RegisterResource(arch->reserved(i));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
120
src/codegen/compiler/context.h
Normal file
120
src/codegen/compiler/context.h
Normal file
@ -0,0 +1,120 @@
|
||||
/* 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_CONTEXT_H
|
||||
#define AVIAN_CODEGEN_COMPILER_CONTEXT_H
|
||||
|
||||
#include "codegen/assembler.h"
|
||||
#include "codegen/compiler.h"
|
||||
|
||||
#include "codegen/compiler/regalloc.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
class Stack;
|
||||
class Local;
|
||||
class Event;
|
||||
class LogicalInstruction;
|
||||
|
||||
class Resource;
|
||||
class RegisterResource;
|
||||
class FrameResource;
|
||||
|
||||
class ConstantPoolNode;
|
||||
|
||||
class ForkState;
|
||||
class MySubroutine;
|
||||
class Block;
|
||||
|
||||
template<class T>
|
||||
class Cell {
|
||||
public:
|
||||
Cell(Cell<T>* next, T* value): next(next), value(value) { }
|
||||
|
||||
Cell<T>* next;
|
||||
T* value;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
unsigned count(Cell<T>* c) {
|
||||
unsigned count = 0;
|
||||
while (c) {
|
||||
++ count;
|
||||
c = c->next;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Cell<T>* reverseDestroy(Cell<T>* cell) {
|
||||
Cell<T>* previous = 0;
|
||||
while (cell) {
|
||||
Cell<T>* next = cell->next;
|
||||
cell->next = previous;
|
||||
previous = cell;
|
||||
cell = next;
|
||||
}
|
||||
return previous;
|
||||
}
|
||||
|
||||
class Context {
|
||||
public:
|
||||
Context(vm::System* system, Assembler* assembler, vm::Zone* zone,
|
||||
Compiler::Client* client);
|
||||
|
||||
vm::System* system;
|
||||
Assembler* assembler;
|
||||
Assembler::Architecture* arch;
|
||||
vm::Zone* zone;
|
||||
Compiler::Client* client;
|
||||
Stack* stack;
|
||||
Local* locals;
|
||||
Cell<Value>* saved;
|
||||
Event* predecessor;
|
||||
LogicalInstruction** logicalCode;
|
||||
const RegisterFile* regFile;
|
||||
RegisterAllocator regAlloc;
|
||||
RegisterResource* registerResources;
|
||||
FrameResource* frameResources;
|
||||
Resource* acquiredResources;
|
||||
ConstantPoolNode* firstConstant;
|
||||
ConstantPoolNode* lastConstant;
|
||||
uint8_t* machineCode;
|
||||
Event* firstEvent;
|
||||
Event* lastEvent;
|
||||
ForkState* forkState;
|
||||
MySubroutine* subroutine;
|
||||
Block* firstBlock;
|
||||
int logicalIp;
|
||||
unsigned constantCount;
|
||||
unsigned logicalCodeLength;
|
||||
unsigned parameterFootprint;
|
||||
unsigned localFootprint;
|
||||
unsigned machineCodeSize;
|
||||
unsigned alignedFrameSize;
|
||||
unsigned availableGeneralRegisterCount;
|
||||
};
|
||||
|
||||
inline Aborter* getAborter(Context* c) {
|
||||
return c->system;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Cell<T>* cons(Context* c, T* value, Cell<T>* next) {
|
||||
return new (c->zone) Cell<T>(next, value);
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif // AVIAN_CODEGEN_COMPILER_CONTEXT_H
|
1698
src/codegen/compiler/event.cpp
Normal file
1698
src/codegen/compiler/event.cpp
Normal file
File diff suppressed because it is too large
Load Diff
171
src/codegen/compiler/event.h
Normal file
171
src/codegen/compiler/event.h
Normal file
@ -0,0 +1,171 @@
|
||||
/* 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_EVENT_H
|
||||
#define AVIAN_CODEGEN_COMPILER_EVENT_H
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
class Context;
|
||||
class CodePromise;
|
||||
class Snapshot;
|
||||
class Link;
|
||||
class Site;
|
||||
class StubRead;
|
||||
|
||||
const bool DebugReads = false;
|
||||
const bool DebugMoves = false;
|
||||
|
||||
class Event {
|
||||
public:
|
||||
Event(Context* c);
|
||||
|
||||
virtual const char* name() = 0;
|
||||
|
||||
virtual void compile(Context* c) = 0;
|
||||
|
||||
virtual bool isBranch() { return false; }
|
||||
|
||||
virtual bool allExits() { return false; }
|
||||
|
||||
virtual Local* locals() { return localsBefore; }
|
||||
|
||||
|
||||
|
||||
void addRead(Context* c, Value* v, Read* r);
|
||||
|
||||
void addRead(Context* c, Value* v, const SiteMask& mask,
|
||||
Value* successor = 0);
|
||||
|
||||
void addReads(Context* c, Value* v, unsigned size,
|
||||
const SiteMask& lowMask, Value* lowSuccessor,
|
||||
const SiteMask& highMask, Value* highSuccessor);
|
||||
|
||||
void addReads(Context* c, Value* v, unsigned size,
|
||||
const SiteMask& lowMask, const SiteMask& highMask);
|
||||
|
||||
CodePromise* makeCodePromise(Context* c);
|
||||
|
||||
bool isUnreachable();
|
||||
|
||||
Event* next;
|
||||
Stack* stackBefore;
|
||||
Local* localsBefore;
|
||||
Stack* stackAfter;
|
||||
Local* localsAfter;
|
||||
CodePromise* promises;
|
||||
Read* reads;
|
||||
Site** junctionSites;
|
||||
Snapshot* snapshots;
|
||||
Link* predecessors;
|
||||
Link* successors;
|
||||
Cell<Link>* visitLinks;
|
||||
Block* block;
|
||||
LogicalInstruction* logicalInstruction;
|
||||
unsigned readCount;
|
||||
};
|
||||
|
||||
class StubReadPair {
|
||||
public:
|
||||
Value* value;
|
||||
StubRead* read;
|
||||
};
|
||||
|
||||
class JunctionState {
|
||||
public:
|
||||
JunctionState(unsigned frameFootprint): frameFootprint(frameFootprint) { }
|
||||
|
||||
unsigned frameFootprint;
|
||||
StubReadPair reads[0];
|
||||
};
|
||||
|
||||
class Link {
|
||||
public:
|
||||
Link(Event* predecessor, Link* nextPredecessor, Event* successor,
|
||||
Link* nextSuccessor, ForkState* forkState):
|
||||
predecessor(predecessor), nextPredecessor(nextPredecessor),
|
||||
successor(successor), nextSuccessor(nextSuccessor), forkState(forkState),
|
||||
junctionState(0)
|
||||
{ }
|
||||
|
||||
unsigned countPredecessors();
|
||||
Link* lastPredecessor();
|
||||
unsigned countSuccessors();
|
||||
|
||||
Event* predecessor;
|
||||
Link* nextPredecessor;
|
||||
Event* successor;
|
||||
Link* nextSuccessor;
|
||||
ForkState* forkState;
|
||||
JunctionState* junctionState;
|
||||
};
|
||||
|
||||
Link*
|
||||
link(Context* c, Event* predecessor, Link* nextPredecessor, Event* successor,
|
||||
Link* nextSuccessor, ForkState* forkState);
|
||||
|
||||
void
|
||||
appendCall(Context* c, Value* address, unsigned flags,
|
||||
TraceHandler* traceHandler, Value* result, unsigned resultSize,
|
||||
Stack* argumentStack, unsigned argumentCount,
|
||||
unsigned stackArgumentFootprint);
|
||||
|
||||
void
|
||||
appendReturn(Context* c, unsigned size, Value* value);
|
||||
|
||||
void
|
||||
appendMove(Context* c, lir::BinaryOperation type, unsigned srcSize,
|
||||
unsigned srcSelectSize, Value* src, unsigned dstSize, Value* dst);
|
||||
|
||||
void
|
||||
appendCombine(Context* c, lir::TernaryOperation type,
|
||||
unsigned firstSize, Value* first,
|
||||
unsigned secondSize, Value* second,
|
||||
unsigned resultSize, Value* result);
|
||||
|
||||
void
|
||||
appendTranslate(Context* c, lir::BinaryOperation type, unsigned firstSize,
|
||||
Value* first, unsigned resultSize, Value* result);
|
||||
|
||||
void
|
||||
appendOperation(Context* c, lir::Operation op);
|
||||
|
||||
void
|
||||
appendMemory(Context* c, Value* base, int displacement, Value* index,
|
||||
unsigned scale, Value* result);
|
||||
|
||||
void
|
||||
appendBranch(Context* c, lir::TernaryOperation type, unsigned size, Value* first,
|
||||
Value* second, Value* address);
|
||||
|
||||
void
|
||||
appendJump(Context* c, lir::UnaryOperation type, Value* address, bool exit = false,
|
||||
bool cleanLocals = false);
|
||||
|
||||
void
|
||||
appendBoundsCheck(Context* c, Value* object, unsigned lengthOffset,
|
||||
Value* index, intptr_t handler);
|
||||
|
||||
void
|
||||
appendFrameSite(Context* c, Value* value, int index);
|
||||
|
||||
void
|
||||
appendSaveLocals(Context* c);
|
||||
|
||||
void
|
||||
appendDummy(Context* c);
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif // AVIAN_CODEGEN_COMPILER_EVENT_H
|
119
src/codegen/compiler/frame.cpp
Normal file
119
src/codegen/compiler/frame.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
/* 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/context.h"
|
||||
#include "codegen/compiler/frame.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
unsigned totalFrameSize(Context* c) {
|
||||
return c->alignedFrameSize
|
||||
+ c->arch->frameHeaderSize()
|
||||
+ c->arch->argumentFootprint(c->parameterFootprint);
|
||||
}
|
||||
|
||||
int frameIndex(Context* c, int localIndex) {
|
||||
assert(c, localIndex >= 0);
|
||||
|
||||
int index = c->alignedFrameSize + c->parameterFootprint - localIndex - 1;
|
||||
|
||||
if (localIndex < static_cast<int>(c->parameterFootprint)) {
|
||||
index += c->arch->frameHeaderSize();
|
||||
} else {
|
||||
index -= c->arch->frameFooterSize();
|
||||
}
|
||||
|
||||
assert(c, index >= 0);
|
||||
assert(c, static_cast<unsigned>(index) < totalFrameSize(c));
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
unsigned frameIndexToOffset(Context* c, unsigned frameIndex) {
|
||||
assert(c, frameIndex < totalFrameSize(c));
|
||||
|
||||
return (frameIndex + c->arch->frameFooterSize()) * vm::TargetBytesPerWord;
|
||||
}
|
||||
|
||||
unsigned offsetToFrameIndex(Context* c, unsigned offset) {
|
||||
assert(c, static_cast<int>
|
||||
((offset / vm::TargetBytesPerWord) - c->arch->frameFooterSize()) >= 0);
|
||||
assert(c, ((offset / vm::TargetBytesPerWord) - c->arch->frameFooterSize())
|
||||
< totalFrameSize(c));
|
||||
|
||||
return (offset / vm::TargetBytesPerWord) - c->arch->frameFooterSize();
|
||||
}
|
||||
|
||||
unsigned frameBase(Context* c) {
|
||||
return c->alignedFrameSize
|
||||
- c->arch->frameReturnAddressSize()
|
||||
- c->arch->frameFooterSize()
|
||||
+ c->arch->frameHeaderSize();
|
||||
}
|
||||
|
||||
FrameIterator::Element::Element(Value* value, unsigned localIndex):
|
||||
value(value), localIndex(localIndex)
|
||||
{ }
|
||||
|
||||
|
||||
int FrameIterator::Element::frameIndex(Context* c) {
|
||||
return compiler::frameIndex(c, this->localIndex);
|
||||
}
|
||||
|
||||
FrameIterator::FrameIterator(Context* c, Stack* stack, Local* locals,
|
||||
bool includeEmpty):
|
||||
stack(stack), locals(locals), localIndex(c->localFootprint - 1),
|
||||
includeEmpty(includeEmpty)
|
||||
{ }
|
||||
|
||||
bool FrameIterator::hasMore() {
|
||||
if (not includeEmpty) {
|
||||
while (stack and stack->value == 0) {
|
||||
stack = stack->next;
|
||||
}
|
||||
|
||||
while (localIndex >= 0 and locals[localIndex].value == 0) {
|
||||
-- localIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return stack != 0 or localIndex >= 0;
|
||||
}
|
||||
|
||||
FrameIterator::Element FrameIterator::next(Context* c) {
|
||||
Value* v;
|
||||
unsigned li;
|
||||
if (stack) {
|
||||
Stack* s = stack;
|
||||
v = s->value;
|
||||
li = s->index + c->localFootprint;
|
||||
stack = stack->next;
|
||||
} else {
|
||||
Local* l = locals + localIndex;
|
||||
v = l->value;
|
||||
li = localIndex;
|
||||
-- localIndex;
|
||||
}
|
||||
return Element(v, li);
|
||||
}
|
||||
|
||||
Stack* stack(Context* c, Value* value, Stack* next) {
|
||||
return new(c->zone) Stack(next ? next->index + 1 : 0, value, next);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
75
src/codegen/compiler/frame.h
Normal file
75
src/codegen/compiler/frame.h
Normal file
@ -0,0 +1,75 @@
|
||||
/* 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_FRAME_H
|
||||
#define AVIAN_CODEGEN_COMPILER_FRAME_H
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
unsigned totalFrameSize(Context* c);
|
||||
|
||||
int frameIndex(Context* c, int localIndex);
|
||||
|
||||
unsigned frameIndexToOffset(Context* c, unsigned frameIndex);
|
||||
|
||||
unsigned offsetToFrameIndex(Context* c, unsigned offset);
|
||||
|
||||
unsigned frameBase(Context* c);
|
||||
|
||||
class FrameIterator {
|
||||
public:
|
||||
class Element {
|
||||
public:
|
||||
Element(Value* value, unsigned localIndex);
|
||||
|
||||
int frameIndex(Context* c);
|
||||
|
||||
Value* const value;
|
||||
const unsigned localIndex;
|
||||
};
|
||||
|
||||
FrameIterator(Context* c, Stack* stack, Local* locals,
|
||||
bool includeEmpty = false);
|
||||
|
||||
bool hasMore();
|
||||
|
||||
Element next(Context* c);
|
||||
|
||||
Stack* stack;
|
||||
Local* locals;
|
||||
int localIndex;
|
||||
bool includeEmpty;
|
||||
};
|
||||
|
||||
class Local {
|
||||
public:
|
||||
Value* value;
|
||||
};
|
||||
|
||||
class Stack {
|
||||
public:
|
||||
Stack(unsigned index, Value* value, Stack* next):
|
||||
index(index), value(value), next(next)
|
||||
{ }
|
||||
|
||||
unsigned index;
|
||||
Value* value;
|
||||
Stack* next;
|
||||
};
|
||||
|
||||
Stack* stack(Context* c, Value* value, Stack* next);
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif // AVIAN_CODEGEN_COMPILER_FRAME_H
|
48
src/codegen/compiler/ir.cpp
Normal file
48
src/codegen/compiler/ir.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
/* 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/compiler/context.h"
|
||||
#include "codegen/compiler/ir.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
LogicalInstruction::LogicalInstruction(int index, Stack* stack, Local* locals):
|
||||
firstEvent(0), lastEvent(0), immediatePredecessor(0), stack(stack),
|
||||
locals(locals), machineOffset(0), subroutine(0), index(index)
|
||||
{ }
|
||||
|
||||
LogicalInstruction* LogicalInstruction::next(Context* c) {
|
||||
LogicalInstruction* i = this;
|
||||
for (unsigned n = i->index + 1; n < c->logicalCodeLength; ++n) {
|
||||
i = c->logicalCode[n];
|
||||
if (i) return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned
|
||||
machineOffset(Context* c, int logicalIp)
|
||||
{
|
||||
return c->logicalCode[logicalIp]->machineOffset->value();
|
||||
}
|
||||
|
||||
Block::Block(Event* head):
|
||||
head(head), nextBlock(0), nextInstruction(0), assemblerBlock(0), start(0)
|
||||
{ }
|
||||
|
||||
Block* block(Context* c, Event* head) {
|
||||
return new(c->zone) Block(head);
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
90
src/codegen/compiler/ir.h
Normal file
90
src/codegen/compiler/ir.h
Normal file
@ -0,0 +1,90 @@
|
||||
/* 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_IR_H
|
||||
#define AVIAN_CODEGEN_COMPILER_IR_H
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
class MultiRead;
|
||||
|
||||
class ForkElement {
|
||||
public:
|
||||
Value* value;
|
||||
MultiRead* read;
|
||||
bool local;
|
||||
};
|
||||
|
||||
class ForkState: public Compiler::State {
|
||||
public:
|
||||
ForkState(Stack* stack, Local* locals, Cell<Value>* saved, Event* predecessor,
|
||||
unsigned logicalIp):
|
||||
stack(stack),
|
||||
locals(locals),
|
||||
saved(saved),
|
||||
predecessor(predecessor),
|
||||
logicalIp(logicalIp),
|
||||
readCount(0)
|
||||
{ }
|
||||
|
||||
Stack* stack;
|
||||
Local* locals;
|
||||
Cell<Value>* saved;
|
||||
Event* predecessor;
|
||||
unsigned logicalIp;
|
||||
unsigned readCount;
|
||||
ForkElement elements[0];
|
||||
};
|
||||
|
||||
class LogicalInstruction {
|
||||
public:
|
||||
LogicalInstruction(int index, Stack* stack, Local* locals);
|
||||
|
||||
LogicalInstruction* next(Context* c);
|
||||
|
||||
Event* firstEvent;
|
||||
Event* lastEvent;
|
||||
LogicalInstruction* immediatePredecessor;
|
||||
Stack* stack;
|
||||
Local* locals;
|
||||
Promise* machineOffset;
|
||||
MySubroutine* subroutine;
|
||||
int index;
|
||||
};
|
||||
|
||||
class MySubroutine: public Compiler::Subroutine {
|
||||
public:
|
||||
MySubroutine(): forkState(0) { }
|
||||
|
||||
ForkState* forkState;
|
||||
};
|
||||
|
||||
class Block {
|
||||
public:
|
||||
Block(Event* head);
|
||||
|
||||
Event* head;
|
||||
Block* nextBlock;
|
||||
LogicalInstruction* nextInstruction;
|
||||
Assembler::Block* assemblerBlock;
|
||||
unsigned start;
|
||||
};
|
||||
|
||||
Block* block(Context* c, Event* head);
|
||||
|
||||
unsigned machineOffset(Context* c, int logicalIp);
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif // AVIAN_CODEGEN_COMPILER_IR_H
|
116
src/codegen/compiler/promise.cpp
Normal file
116
src/codegen/compiler/promise.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
/* 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/context.h"
|
||||
#include "codegen/compiler/promise.h"
|
||||
#include "codegen/compiler/ir.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
CodePromise::CodePromise(Context* c, CodePromise* next):
|
||||
c(c), offset(0), next(next)
|
||||
{ }
|
||||
|
||||
CodePromise::CodePromise(Context* c, Promise* offset):
|
||||
c(c), offset(offset), next(0)
|
||||
{ }
|
||||
|
||||
int64_t CodePromise::value() {
|
||||
if (resolved()) {
|
||||
return reinterpret_cast<intptr_t>(c->machineCode + offset->value());
|
||||
}
|
||||
|
||||
abort(c);
|
||||
}
|
||||
|
||||
bool CodePromise::resolved() {
|
||||
return c->machineCode != 0 and offset and offset->resolved();
|
||||
}
|
||||
|
||||
CodePromise* codePromise(Context* c, Promise* offset) {
|
||||
return new (c->zone) CodePromise(c, offset);
|
||||
}
|
||||
|
||||
Promise* shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask) {
|
||||
return new (c->zone) ShiftMaskPromise(base, shift, mask);
|
||||
}
|
||||
|
||||
Promise* combinedPromise(Context* c, Promise* low, Promise* high) {
|
||||
return new (c->zone) CombinedPromise(low, high);
|
||||
}
|
||||
|
||||
Promise* resolvedPromise(Context* c, int64_t value) {
|
||||
return new (c->zone) ResolvedPromise(value);
|
||||
}
|
||||
|
||||
class IpPromise: public Promise {
|
||||
public:
|
||||
IpPromise(Context* c, int logicalIp):
|
||||
c(c),
|
||||
logicalIp(logicalIp)
|
||||
{ }
|
||||
|
||||
virtual int64_t value() {
|
||||
if (resolved()) {
|
||||
return reinterpret_cast<intptr_t>
|
||||
(c->machineCode + machineOffset(c, logicalIp));
|
||||
}
|
||||
|
||||
abort(c);
|
||||
}
|
||||
|
||||
virtual bool resolved() {
|
||||
return c->machineCode != 0
|
||||
and c->logicalCode[logicalIp]->machineOffset->resolved();
|
||||
}
|
||||
|
||||
Context* c;
|
||||
int logicalIp;
|
||||
};
|
||||
|
||||
Promise* ipPromise(Context* c, int logicalIp) {
|
||||
return new (c->zone) IpPromise(c, logicalIp);
|
||||
}
|
||||
|
||||
|
||||
class PoolPromise: public Promise {
|
||||
public:
|
||||
PoolPromise(Context* c, int key): c(c), key(key) { }
|
||||
|
||||
virtual int64_t value() {
|
||||
if (resolved()) {
|
||||
return reinterpret_cast<int64_t>
|
||||
(c->machineCode + vm::pad(c->machineCodeSize, vm::TargetBytesPerWord)
|
||||
+ (key * vm::TargetBytesPerWord));
|
||||
}
|
||||
|
||||
abort(c);
|
||||
}
|
||||
|
||||
virtual bool resolved() {
|
||||
return c->machineCode != 0;
|
||||
}
|
||||
|
||||
Context* c;
|
||||
int key;
|
||||
};
|
||||
|
||||
Promise* poolPromise(Context* c, int key) {
|
||||
return new(c->zone) PoolPromise(c, key);
|
||||
}
|
||||
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
50
src/codegen/compiler/promise.h
Normal file
50
src/codegen/compiler/promise.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* 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_PROMISE_H
|
||||
#define AVIAN_CODEGEN_COMPILER_PROMISE_H
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
|
||||
class CodePromise: public Promise {
|
||||
public:
|
||||
CodePromise(Context* c, CodePromise* next);
|
||||
|
||||
CodePromise(Context* c, Promise* offset);
|
||||
|
||||
virtual int64_t value();
|
||||
|
||||
virtual bool resolved();
|
||||
|
||||
Context* c;
|
||||
Promise* offset;
|
||||
CodePromise* next;
|
||||
};
|
||||
|
||||
CodePromise* codePromise(Context* c, Promise* offset);
|
||||
|
||||
Promise* shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask);
|
||||
|
||||
Promise* combinedPromise(Context* c, Promise* low, Promise* high);
|
||||
|
||||
Promise* resolvedPromise(Context* c, int64_t value);
|
||||
|
||||
Promise* ipPromise(Context* c, int logicalIp);
|
||||
|
||||
Promise* poolPromise(Context* c, int key);
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif // AVIAN_CODEGEN_COMPILER_PROMISE_H
|
191
src/codegen/compiler/read.cpp
Normal file
191
src/codegen/compiler/read.cpp
Normal file
@ -0,0 +1,191 @@
|
||||
/* 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/context.h"
|
||||
#include "codegen/compiler/value.h"
|
||||
#include "codegen/compiler/site.h"
|
||||
#include "codegen/compiler/resource.h"
|
||||
#include "codegen/compiler/read.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
|
||||
SingleRead::SingleRead(const SiteMask& mask, Value* successor):
|
||||
next_(0), mask(mask), high_(0), successor_(successor)
|
||||
{ }
|
||||
|
||||
bool SingleRead::intersect(SiteMask* mask, unsigned) {
|
||||
*mask = mask->intersectionWith(this->mask);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Value* SingleRead::high(Context*) {
|
||||
return high_;
|
||||
}
|
||||
|
||||
Value* SingleRead::successor() {
|
||||
return successor_;
|
||||
}
|
||||
|
||||
bool SingleRead::valid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void SingleRead::append(Context* c UNUSED, Read* r) {
|
||||
assert(c, next_ == 0);
|
||||
next_ = r;
|
||||
}
|
||||
|
||||
Read* SingleRead::next(Context*) {
|
||||
return next_;
|
||||
}
|
||||
|
||||
MultiRead::MultiRead():
|
||||
reads(0), lastRead(0), firstTarget(0), lastTarget(0), visited(false)
|
||||
{ }
|
||||
|
||||
bool MultiRead::intersect(SiteMask* mask, unsigned depth) {
|
||||
if (depth > 0) {
|
||||
// short-circuit recursion to avoid poor performance in
|
||||
// deeply-nested branches
|
||||
return reads != 0;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
if (not visited) {
|
||||
visited = true;
|
||||
for (Cell<Read>** cell = &reads; *cell;) {
|
||||
Read* r = (*cell)->value;
|
||||
bool valid = r->intersect(mask, depth + 1);
|
||||
if (valid) {
|
||||
result = true;
|
||||
cell = &((*cell)->next);
|
||||
} else {
|
||||
*cell = (*cell)->next;
|
||||
}
|
||||
}
|
||||
visited = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Value* MultiRead::successor() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool MultiRead::valid() {
|
||||
bool result = false;
|
||||
if (not visited) {
|
||||
visited = true;
|
||||
for (Cell<Read>** cell = &reads; *cell;) {
|
||||
Read* r = (*cell)->value;
|
||||
if (r->valid()) {
|
||||
result = true;
|
||||
cell = &((*cell)->next);
|
||||
} else {
|
||||
*cell = (*cell)->next;
|
||||
}
|
||||
}
|
||||
visited = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void MultiRead::append(Context* c, Read* r) {
|
||||
Cell<Read>* cell = cons<Read>(c, r, 0);
|
||||
if (lastRead == 0) {
|
||||
reads = cell;
|
||||
} else {
|
||||
lastRead->next = cell;
|
||||
}
|
||||
lastRead = cell;
|
||||
|
||||
// fprintf(stderr, "append %p to %p for %p\n", r, lastTarget, this);
|
||||
|
||||
lastTarget->value = r;
|
||||
}
|
||||
|
||||
Read* MultiRead::next(Context* c) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
void MultiRead::allocateTarget(Context* c) {
|
||||
Cell<Read>* cell = cons<Read>(c, 0, 0);
|
||||
|
||||
// fprintf(stderr, "allocate target for %p: %p\n", this, cell);
|
||||
|
||||
if (lastTarget) {
|
||||
lastTarget->next = cell;
|
||||
} else {
|
||||
firstTarget = cell;
|
||||
}
|
||||
lastTarget = cell;
|
||||
}
|
||||
|
||||
Read* MultiRead::nextTarget() {
|
||||
// fprintf(stderr, "next target for %p: %p\n", this, firstTarget);
|
||||
|
||||
Read* r = firstTarget->value;
|
||||
firstTarget = firstTarget->next;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
StubRead::StubRead():
|
||||
next_(0), read(0), visited(false), valid_(true)
|
||||
{ }
|
||||
|
||||
bool StubRead::intersect(SiteMask* mask, unsigned depth) {
|
||||
if (not visited) {
|
||||
visited = true;
|
||||
if (read) {
|
||||
bool valid = read->intersect(mask, depth);
|
||||
if (not valid) {
|
||||
read = 0;
|
||||
}
|
||||
}
|
||||
visited = false;
|
||||
}
|
||||
return valid_;
|
||||
}
|
||||
|
||||
Value* StubRead::successor() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool StubRead::valid() {
|
||||
return valid_;
|
||||
}
|
||||
|
||||
void StubRead::append(Context* c UNUSED, Read* r) {
|
||||
assert(c, next_ == 0);
|
||||
next_ = r;
|
||||
}
|
||||
|
||||
Read* StubRead::next(Context*) {
|
||||
return next_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SingleRead* read(Context* c, const SiteMask& mask, Value* successor) {
|
||||
assert(c, (mask.typeMask != 1 << lir::MemoryOperand) or mask.frameIndex >= 0);
|
||||
|
||||
return new(c->zone) SingleRead(mask, successor);
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
125
src/codegen/compiler/read.h
Normal file
125
src/codegen/compiler/read.h
Normal file
@ -0,0 +1,125 @@
|
||||
/* 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 Context;
|
||||
class SiteMask;
|
||||
class Value;
|
||||
class Event;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
inline bool valid(Read* r) {
|
||||
return r and r->valid();
|
||||
}
|
||||
|
||||
class SingleRead: public Read {
|
||||
public:
|
||||
SingleRead(const SiteMask& mask, Value* successor);
|
||||
|
||||
virtual bool intersect(SiteMask* mask, unsigned);
|
||||
|
||||
virtual Value* high(Context*);
|
||||
|
||||
virtual Value* successor();
|
||||
|
||||
virtual bool valid();
|
||||
|
||||
virtual void append(Context* c UNUSED, Read* r);
|
||||
|
||||
virtual Read* next(Context*);
|
||||
|
||||
Read* next_;
|
||||
SiteMask mask;
|
||||
Value* high_;
|
||||
Value* successor_;
|
||||
};
|
||||
|
||||
|
||||
class MultiRead: public Read {
|
||||
public:
|
||||
MultiRead();
|
||||
|
||||
virtual bool intersect(SiteMask* mask, unsigned depth);
|
||||
|
||||
virtual Value* successor();
|
||||
|
||||
virtual bool valid();
|
||||
|
||||
virtual void append(Context* c, Read* r);
|
||||
|
||||
virtual Read* next(Context* c);
|
||||
|
||||
void allocateTarget(Context* c);
|
||||
|
||||
Read* nextTarget();
|
||||
|
||||
Cell<Read>* reads;
|
||||
Cell<Read>* lastRead;
|
||||
Cell<Read>* firstTarget;
|
||||
Cell<Read>* lastTarget;
|
||||
bool visited;
|
||||
};
|
||||
|
||||
class StubRead: public Read {
|
||||
public:
|
||||
StubRead();
|
||||
|
||||
virtual bool intersect(SiteMask* mask, unsigned depth);
|
||||
|
||||
virtual Value* successor();
|
||||
|
||||
virtual bool valid();
|
||||
|
||||
virtual void append(Context* c UNUSED, Read* r);
|
||||
|
||||
virtual Read* next(Context*);
|
||||
|
||||
Read* next_;
|
||||
Read* read;
|
||||
bool visited;
|
||||
bool valid_;
|
||||
};
|
||||
|
||||
SingleRead* read(Context* c, const SiteMask& mask, Value* successor = 0);
|
||||
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif // AVIAN_CODEGEN_COMPILER_READ_H
|
300
src/codegen/compiler/regalloc.cpp
Normal file
300
src/codegen/compiler/regalloc.cpp
Normal file
@ -0,0 +1,300 @@
|
||||
/* 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)
|
||||
{ }
|
||||
|
||||
|
||||
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 (r->value->uniqueSite(c, 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
|
226
src/codegen/compiler/resource.cpp
Normal file
226
src/codegen/compiler/resource.cpp
Normal file
@ -0,0 +1,226 @@
|
||||
/* 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/compiler/context.h"
|
||||
#include "codegen/compiler/resource.h"
|
||||
#include "codegen/compiler/value.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
const bool DebugResources = false;
|
||||
|
||||
|
||||
void steal(Context* c, Resource* r, Value* thief);
|
||||
|
||||
void decrementAvailableGeneralRegisterCount(Context* c) {
|
||||
assert(c, c->availableGeneralRegisterCount);
|
||||
-- c->availableGeneralRegisterCount;
|
||||
|
||||
if (DebugResources) {
|
||||
fprintf(stderr, "%d registers available\n",
|
||||
c->availableGeneralRegisterCount);
|
||||
}
|
||||
}
|
||||
|
||||
void incrementAvailableGeneralRegisterCount(Context* c) {
|
||||
++ c->availableGeneralRegisterCount;
|
||||
|
||||
if (DebugResources) {
|
||||
fprintf(stderr, "%d registers available\n",
|
||||
c->availableGeneralRegisterCount);
|
||||
}
|
||||
}
|
||||
|
||||
void freezeResource(Context* c, Resource* r, Value* v) {
|
||||
if (DebugResources) {
|
||||
char buffer[256]; r->toString(c, buffer, 256);
|
||||
fprintf(stderr, "%p freeze %s to %d\n", v, buffer, r->freezeCount + 1);
|
||||
}
|
||||
|
||||
++ r->freezeCount;
|
||||
}
|
||||
|
||||
void thawResource(Context* c, Resource* r, Value* v) {
|
||||
if (not r->reserved) {
|
||||
if (DebugResources) {
|
||||
char buffer[256]; r->toString(c, buffer, 256);
|
||||
fprintf(stderr, "%p thaw %s to %d\n", v, buffer, r->freezeCount - 1);
|
||||
}
|
||||
|
||||
assert(c, r->freezeCount);
|
||||
|
||||
-- r->freezeCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Resource::Resource(bool reserved):
|
||||
value(0), site(0), previousAcquired(0), nextAcquired(0), freezeCount(0),
|
||||
referenceCount(0), reserved(reserved)
|
||||
{ }
|
||||
|
||||
RegisterResource::RegisterResource(bool reserved):
|
||||
Resource(reserved)
|
||||
{ }
|
||||
|
||||
void RegisterResource::freeze(Context* c, Value* v) {
|
||||
if (not reserved) {
|
||||
freezeResource(c, this, v);
|
||||
|
||||
if (freezeCount == 1
|
||||
and ((1 << index(c)) & c->regFile->generalRegisters.mask))
|
||||
{
|
||||
decrementAvailableGeneralRegisterCount(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterResource::thaw(Context* c, Value* v) {
|
||||
if (not reserved) {
|
||||
thawResource(c, this, v);
|
||||
|
||||
if (freezeCount == 0
|
||||
and ((1 << index(c)) & c->regFile->generalRegisters.mask))
|
||||
{
|
||||
incrementAvailableGeneralRegisterCount(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned RegisterResource::toString(Context* c, char* buffer, unsigned bufferSize) {
|
||||
return vm::snprintf(buffer, bufferSize, "register %d", index(c));
|
||||
}
|
||||
|
||||
unsigned RegisterResource::index(Context* c) {
|
||||
return this - c->registerResources;
|
||||
}
|
||||
|
||||
void RegisterResource::increment(Context* c) {
|
||||
if (not this->reserved) {
|
||||
if (DebugResources) {
|
||||
char buffer[256]; this->toString(c, buffer, 256);
|
||||
fprintf(stderr, "increment %s to %d\n", buffer, this->referenceCount + 1);
|
||||
}
|
||||
|
||||
++ this->referenceCount;
|
||||
|
||||
if (this->referenceCount == 1
|
||||
and ((1 << this->index(c)) & c->regFile->generalRegisters.mask))
|
||||
{
|
||||
decrementAvailableGeneralRegisterCount(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterResource::decrement(Context* c) {
|
||||
if (not this->reserved) {
|
||||
if (DebugResources) {
|
||||
char buffer[256]; this->toString(c, buffer, 256);
|
||||
fprintf(stderr, "decrement %s to %d\n", buffer, this->referenceCount - 1);
|
||||
}
|
||||
|
||||
assert(c, this->referenceCount > 0);
|
||||
|
||||
-- this->referenceCount;
|
||||
|
||||
if (this->referenceCount == 0
|
||||
and ((1 << this->index(c)) & c->regFile->generalRegisters.mask))
|
||||
{
|
||||
incrementAvailableGeneralRegisterCount(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FrameResource::freeze(Context* c, Value* v) {
|
||||
freezeResource(c, this, v);
|
||||
}
|
||||
|
||||
void FrameResource::thaw(Context* c, Value* v) {
|
||||
thawResource(c, this, v);
|
||||
}
|
||||
|
||||
unsigned FrameResource::toString(Context* c, char* buffer, unsigned bufferSize) {
|
||||
return vm::snprintf(buffer, bufferSize, "frame %d", index(c));
|
||||
}
|
||||
|
||||
unsigned FrameResource::index(Context* c) {
|
||||
return this - c->frameResources;
|
||||
}
|
||||
|
||||
|
||||
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
|
77
src/codegen/compiler/resource.h
Normal file
77
src/codegen/compiler/resource.h
Normal file
@ -0,0 +1,77 @@
|
||||
/* 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_RESOURCE_H
|
||||
#define AVIAN_CODEGEN_COMPILER_RESOURCE_H
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
class Context;
|
||||
class Value;
|
||||
class Site;
|
||||
|
||||
class Resource {
|
||||
public:
|
||||
Resource(bool reserved = false);
|
||||
|
||||
virtual void freeze(Context*, Value*) = 0;
|
||||
|
||||
virtual void thaw(Context*, Value*) = 0;
|
||||
|
||||
virtual unsigned toString(Context*, char*, unsigned) = 0;
|
||||
|
||||
Value* value;
|
||||
Site* site;
|
||||
Resource* previousAcquired;
|
||||
Resource* nextAcquired;
|
||||
uint8_t freezeCount;
|
||||
uint8_t referenceCount;
|
||||
bool reserved;
|
||||
};
|
||||
|
||||
class RegisterResource: public Resource {
|
||||
public:
|
||||
RegisterResource(bool reserved);
|
||||
|
||||
virtual void freeze(Context*, Value*);
|
||||
|
||||
virtual void thaw(Context*, Value*);
|
||||
|
||||
virtual unsigned toString(Context* c, char* buffer, unsigned bufferSize);
|
||||
|
||||
virtual unsigned index(Context*);
|
||||
|
||||
void increment(Context*);
|
||||
|
||||
void decrement(Context*);
|
||||
};
|
||||
|
||||
class FrameResource: public Resource {
|
||||
public:
|
||||
virtual void freeze(Context*, Value*);
|
||||
|
||||
virtual void thaw(Context*, Value*);
|
||||
|
||||
virtual unsigned toString(Context* c, char* buffer, unsigned bufferSize);
|
||||
|
||||
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
|
||||
|
||||
#endif // AVIAN_CODEGEN_COMPILER_RESOURCE_H
|
628
src/codegen/compiler/site.cpp
Normal file
628
src/codegen/compiler/site.cpp
Normal file
@ -0,0 +1,628 @@
|
||||
/* 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/context.h"
|
||||
#include "codegen/compiler/value.h"
|
||||
#include "codegen/compiler/site.h"
|
||||
#include "codegen/compiler/resource.h"
|
||||
#include "codegen/compiler/frame.h"
|
||||
#include "codegen/compiler/promise.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
|
||||
|
||||
int intersectFrameIndexes(int a, int b) {
|
||||
if (a == NoFrameIndex or b == NoFrameIndex) return NoFrameIndex;
|
||||
if (a == AnyFrameIndex) return b;
|
||||
if (b == AnyFrameIndex) return a;
|
||||
if (a == b) return a;
|
||||
return NoFrameIndex;
|
||||
}
|
||||
|
||||
|
||||
SiteMask SiteMask::intersectionWith(const SiteMask& b) {
|
||||
return SiteMask(typeMask & b.typeMask, registerMask & b.registerMask,
|
||||
intersectFrameIndexes(frameIndex, b.frameIndex));
|
||||
}
|
||||
|
||||
SiteIterator::SiteIterator(Context* c, Value* v, bool includeBuddies,
|
||||
bool includeNextWord):
|
||||
c(c),
|
||||
originalValue(v),
|
||||
currentValue(v),
|
||||
includeBuddies(includeBuddies),
|
||||
includeNextWord(includeNextWord),
|
||||
pass(0),
|
||||
next_(findNext(&(v->sites))),
|
||||
previous(0)
|
||||
{ }
|
||||
|
||||
Site** SiteIterator::findNext(Site** p) {
|
||||
while (true) {
|
||||
if (*p) {
|
||||
if (pass == 0 or (*p)->registerSize(c) > vm::TargetBytesPerWord) {
|
||||
return p;
|
||||
} else {
|
||||
p = &((*p)->next);
|
||||
}
|
||||
} else {
|
||||
if (includeBuddies) {
|
||||
Value* v = currentValue->buddy;
|
||||
if (v != originalValue) {
|
||||
currentValue = v;
|
||||
p = &(v->sites);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (includeNextWord and pass == 0) {
|
||||
Value* v = originalValue->nextWord;
|
||||
if (v != originalValue) {
|
||||
pass = 1;
|
||||
originalValue = v;
|
||||
currentValue = v;
|
||||
p = &(v->sites);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SiteIterator::hasMore() {
|
||||
if (previous) {
|
||||
next_ = findNext(&((*previous)->next));
|
||||
previous = 0;
|
||||
}
|
||||
return next_ != 0;
|
||||
}
|
||||
|
||||
Site* SiteIterator::next() {
|
||||
previous = next_;
|
||||
return *previous;
|
||||
}
|
||||
|
||||
void SiteIterator::remove(Context* c) {
|
||||
(*previous)->release(c, originalValue);
|
||||
*previous = (*previous)->next;
|
||||
next_ = findNext(previous);
|
||||
previous = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned Site::registerSize(Context*) {
|
||||
return vm::TargetBytesPerWord;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Site* constantSite(Context* c, Promise* value) {
|
||||
return new(c->zone) ConstantSite(value);
|
||||
}
|
||||
|
||||
Site* constantSite(Context* c, int64_t value) {
|
||||
return constantSite(c, resolvedPromise(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);
|
||||
}
|
||||
|
||||
MemorySite::MemorySite(int base, int offset, int index, unsigned scale):
|
||||
acquired(false), base(base), offset(offset), index(index), scale(scale)
|
||||
{ }
|
||||
|
||||
unsigned MemorySite::toString(Context*, char* buffer, unsigned bufferSize) {
|
||||
if (acquired) {
|
||||
return vm::snprintf(buffer, bufferSize, "memory %d 0x%x %d %d",
|
||||
base, offset, index, scale);
|
||||
} else {
|
||||
return vm::snprintf(buffer, bufferSize, "memory unacquired");
|
||||
}
|
||||
}
|
||||
|
||||
unsigned MemorySite::copyCost(Context* c, Site* s) {
|
||||
assert(c, acquired);
|
||||
|
||||
if (s and
|
||||
(this == s or
|
||||
(s->type(c) == lir::MemoryOperand
|
||||
and static_cast<MemorySite*>(s)->base == base
|
||||
and static_cast<MemorySite*>(s)->offset == offset
|
||||
and static_cast<MemorySite*>(s)->index == index
|
||||
and static_cast<MemorySite*>(s)->scale == scale)))
|
||||
{
|
||||
return 0;
|
||||
} else {
|
||||
return MemoryCopyCost;
|
||||
}
|
||||
}
|
||||
|
||||
bool MemorySite::conflicts(const SiteMask& mask) {
|
||||
return (mask.typeMask & (1 << lir::RegisterOperand)) != 0
|
||||
and (((1 << base) & mask.registerMask) == 0
|
||||
or (index != lir::NoRegister
|
||||
and ((1 << index) & mask.registerMask) == 0));
|
||||
}
|
||||
|
||||
bool MemorySite::match(Context* c, const SiteMask& mask) {
|
||||
assert(c, acquired);
|
||||
|
||||
if (mask.typeMask & (1 << lir::MemoryOperand)) {
|
||||
if (mask.frameIndex >= 0) {
|
||||
if (base == c->arch->stack()) {
|
||||
assert(c, index == lir::NoRegister);
|
||||
return static_cast<int>(frameIndexToOffset(c, mask.frameIndex))
|
||||
== offset;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MemorySite::loneMatch(Context* c, const SiteMask& mask) {
|
||||
assert(c, acquired);
|
||||
|
||||
if (mask.typeMask & (1 << lir::MemoryOperand)) {
|
||||
if (base == c->arch->stack()) {
|
||||
assert(c, index == lir::NoRegister);
|
||||
|
||||
if (mask.frameIndex == AnyFrameIndex) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MemorySite::matchNextWord(Context* c, Site* s, unsigned index) {
|
||||
if (s->type(c) == lir::MemoryOperand) {
|
||||
MemorySite* ms = static_cast<MemorySite*>(s);
|
||||
return ms->base == this->base
|
||||
and ((index == 1 and ms->offset == static_cast<int>
|
||||
(this->offset + vm::TargetBytesPerWord))
|
||||
or (index == 0 and this->offset == static_cast<int>
|
||||
(ms->offset + vm::TargetBytesPerWord)))
|
||||
and ms->index == this->index
|
||||
and ms->scale == this->scale;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void MemorySite::acquire(Context* c, Value* v) {
|
||||
c->registerResources[base].increment(c);
|
||||
if (index != lir::NoRegister) {
|
||||
c->registerResources[index].increment(c);
|
||||
}
|
||||
|
||||
if (base == c->arch->stack()) {
|
||||
assert(c, index == lir::NoRegister);
|
||||
assert
|
||||
(c, not c->frameResources[offsetToFrameIndex(c, offset)].reserved);
|
||||
|
||||
compiler::acquire
|
||||
(c, c->frameResources + offsetToFrameIndex(c, offset), v, this);
|
||||
}
|
||||
|
||||
acquired = true;
|
||||
}
|
||||
|
||||
void MemorySite::release(Context* c, Value* v) {
|
||||
if (base == c->arch->stack()) {
|
||||
assert(c, index == lir::NoRegister);
|
||||
assert
|
||||
(c, not c->frameResources[offsetToFrameIndex(c, offset)].reserved);
|
||||
|
||||
compiler::release
|
||||
(c, c->frameResources + offsetToFrameIndex(c, offset), v, this);
|
||||
}
|
||||
|
||||
c->registerResources[base].decrement(c);
|
||||
if (index != lir::NoRegister) {
|
||||
c->registerResources[index].decrement(c);
|
||||
}
|
||||
|
||||
acquired = false;
|
||||
}
|
||||
|
||||
void MemorySite::freeze(Context* c, Value* v) {
|
||||
if (base == c->arch->stack()) {
|
||||
c->frameResources[offsetToFrameIndex(c, offset)].freeze(c, v);
|
||||
} else {
|
||||
c->registerResources[base].increment(c);
|
||||
if (index != lir::NoRegister) {
|
||||
c->registerResources[index].increment(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MemorySite::thaw(Context* c, Value* v) {
|
||||
if (base == c->arch->stack()) {
|
||||
c->frameResources[offsetToFrameIndex(c, offset)].thaw(c, v);
|
||||
} else {
|
||||
c->registerResources[base].decrement(c);
|
||||
if (index != lir::NoRegister) {
|
||||
c->registerResources[index].decrement(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MemorySite::frozen(Context* c) {
|
||||
return base == c->arch->stack()
|
||||
and c->frameResources[offsetToFrameIndex(c, offset)].freezeCount != 0;
|
||||
}
|
||||
|
||||
lir::OperandType MemorySite::type(Context*) {
|
||||
return lir::MemoryOperand;
|
||||
}
|
||||
|
||||
void MemorySite::asAssemblerOperand(Context* c UNUSED, Site* high UNUSED,
|
||||
lir::Operand* result)
|
||||
{
|
||||
// todo: endianness?
|
||||
assert(c, high == this
|
||||
or (static_cast<MemorySite*>(high)->base == base
|
||||
and static_cast<MemorySite*>(high)->offset
|
||||
== static_cast<int>(offset + vm::TargetBytesPerWord)
|
||||
and static_cast<MemorySite*>(high)->index == index
|
||||
and static_cast<MemorySite*>(high)->scale == scale));
|
||||
|
||||
assert(c, acquired);
|
||||
|
||||
new (result) lir::Memory(base, offset, index, scale);
|
||||
}
|
||||
|
||||
Site* MemorySite::copy(Context* c) {
|
||||
return memorySite(c, base, offset, index, scale);
|
||||
}
|
||||
|
||||
Site* MemorySite::copyHalf(Context* c, bool add) {
|
||||
if (add) {
|
||||
return memorySite(c, base, offset + vm::TargetBytesPerWord, index, scale);
|
||||
} else {
|
||||
return copy(c);
|
||||
}
|
||||
}
|
||||
|
||||
Site* MemorySite::copyLow(Context* c) {
|
||||
return copyHalf(c, c->arch->bigEndian());
|
||||
}
|
||||
|
||||
Site* MemorySite::copyHigh(Context* c) {
|
||||
return copyHalf(c, not c->arch->bigEndian());
|
||||
}
|
||||
|
||||
Site* MemorySite::makeNextWord(Context* c, unsigned index) {
|
||||
return memorySite
|
||||
(c, base, offset + ((index == 1) xor c->arch->bigEndian()
|
||||
? vm::TargetBytesPerWord : -vm::TargetBytesPerWord),
|
||||
this->index, scale);
|
||||
}
|
||||
|
||||
SiteMask MemorySite::mask(Context* c) {
|
||||
return SiteMask(1 << lir::MemoryOperand, 0, (base == c->arch->stack())
|
||||
? static_cast<int>(offsetToFrameIndex(c, offset))
|
||||
: NoFrameIndex);
|
||||
}
|
||||
|
||||
SiteMask MemorySite::nextWordMask(Context* c, unsigned index) {
|
||||
int frameIndex;
|
||||
if (base == c->arch->stack()) {
|
||||
assert(c, this->index == lir::NoRegister);
|
||||
frameIndex = static_cast<int>(offsetToFrameIndex(c, offset))
|
||||
+ ((index == 1) xor c->arch->bigEndian() ? 1 : -1);
|
||||
} else {
|
||||
frameIndex = NoFrameIndex;
|
||||
}
|
||||
return SiteMask(1 << lir::MemoryOperand, 0, frameIndex);
|
||||
}
|
||||
|
||||
bool MemorySite::isVolatile(Context* c) {
|
||||
return base != c->arch->stack();
|
||||
}
|
||||
|
||||
|
||||
MemorySite* memorySite(Context* c, int base, int offset, int index, unsigned scale) {
|
||||
return new(c->zone) MemorySite(base, offset, index, scale);
|
||||
}
|
||||
|
||||
MemorySite* frameSite(Context* c, int frameIndex) {
|
||||
assert(c, frameIndex >= 0);
|
||||
return memorySite
|
||||
(c, c->arch->stack(), frameIndexToOffset(c, frameIndex), lir::NoRegister, 0);
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
311
src/codegen/compiler/site.h
Normal file
311
src/codegen/compiler/site.h
Normal file
@ -0,0 +1,311 @@
|
||||
/* 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_SITE_H
|
||||
#define AVIAN_CODEGEN_COMPILER_SITE_H
|
||||
|
||||
#include "codegen/compiler/value.h"
|
||||
#include "codegen/compiler/context.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
class Context;
|
||||
|
||||
const unsigned RegisterCopyCost = 1;
|
||||
const unsigned AddressCopyCost = 2;
|
||||
const unsigned ConstantCopyCost = 3;
|
||||
const unsigned MemoryCopyCost = 4;
|
||||
const unsigned CopyPenalty = 10;
|
||||
|
||||
class SiteMask {
|
||||
public:
|
||||
SiteMask(): typeMask(~0), registerMask(~0), frameIndex(AnyFrameIndex) { }
|
||||
|
||||
SiteMask(uint8_t typeMask, uint32_t registerMask, int frameIndex):
|
||||
typeMask(typeMask), registerMask(registerMask), frameIndex(frameIndex)
|
||||
{ }
|
||||
|
||||
SiteMask intersectionWith(const SiteMask& b);
|
||||
|
||||
static SiteMask fixedRegisterMask(int number) {
|
||||
return SiteMask(1 << lir::RegisterOperand, 1 << number, NoFrameIndex);
|
||||
}
|
||||
|
||||
uint8_t typeMask;
|
||||
uint32_t registerMask;
|
||||
int frameIndex;
|
||||
};
|
||||
|
||||
class Site {
|
||||
public:
|
||||
Site(): next(0) { }
|
||||
|
||||
virtual Site* readTarget(Context*, Read*) { return this; }
|
||||
|
||||
virtual unsigned toString(Context*, char*, unsigned) = 0;
|
||||
|
||||
virtual unsigned copyCost(Context*, Site*) = 0;
|
||||
|
||||
virtual bool match(Context*, const SiteMask&) = 0;
|
||||
|
||||
virtual bool loneMatch(Context*, const SiteMask&) = 0;
|
||||
|
||||
virtual bool matchNextWord(Context*, Site*, unsigned) = 0;
|
||||
|
||||
virtual void acquire(Context*, Value*) { }
|
||||
|
||||
virtual void release(Context*, Value*) { }
|
||||
|
||||
virtual void freeze(Context*, Value*) { }
|
||||
|
||||
virtual void thaw(Context*, Value*) { }
|
||||
|
||||
virtual bool frozen(Context*) { return false; }
|
||||
|
||||
virtual lir::OperandType type(Context*) = 0;
|
||||
|
||||
virtual void asAssemblerOperand(Context*, Site*, lir::Operand*) = 0;
|
||||
|
||||
virtual Site* copy(Context*) = 0;
|
||||
|
||||
virtual Site* copyLow(Context*) = 0;
|
||||
|
||||
virtual Site* copyHigh(Context*) = 0;
|
||||
|
||||
virtual Site* makeNextWord(Context*, unsigned) = 0;
|
||||
|
||||
virtual SiteMask mask(Context*) = 0;
|
||||
|
||||
virtual SiteMask nextWordMask(Context*, unsigned) = 0;
|
||||
|
||||
virtual unsigned registerSize(Context*);
|
||||
|
||||
virtual unsigned registerMask(Context*) { return 0; }
|
||||
|
||||
virtual bool isVolatile(Context*) { return false; }
|
||||
|
||||
Site* next;
|
||||
};
|
||||
|
||||
class SiteIterator {
|
||||
public:
|
||||
SiteIterator(Context* c, Value* v, bool includeBuddies = true,
|
||||
bool includeNextWord = true);
|
||||
|
||||
Site** findNext(Site** p);
|
||||
bool hasMore();
|
||||
Site* next();
|
||||
void remove(Context* c);
|
||||
|
||||
Context* c;
|
||||
Value* originalValue;
|
||||
Value* currentValue;
|
||||
bool includeBuddies;
|
||||
bool includeNextWord;
|
||||
uint8_t pass;
|
||||
Site** next_;
|
||||
Site** previous;
|
||||
};
|
||||
|
||||
Site* constantSite(Context* c, Promise* value);
|
||||
Site* constantSite(Context* c, int64_t value);
|
||||
|
||||
Promise* combinedPromise(Context* c, Promise* low, Promise* high);
|
||||
Promise* shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask);
|
||||
|
||||
class ConstantSite: public Site {
|
||||
public:
|
||||
ConstantSite(Promise* value): value(value) { }
|
||||
|
||||
virtual unsigned toString(Context*, char* buffer, unsigned bufferSize) {
|
||||
if (value->resolved()) {
|
||||
return vm::snprintf
|
||||
(buffer, bufferSize, "constant %" LLD, value->value());
|
||||
} else {
|
||||
return vm::snprintf(buffer, bufferSize, "constant unresolved");
|
||||
}
|
||||
}
|
||||
|
||||
virtual unsigned copyCost(Context*, Site* s) {
|
||||
return (s == this ? 0 : ConstantCopyCost);
|
||||
}
|
||||
|
||||
virtual bool match(Context*, const SiteMask& mask) {
|
||||
return mask.typeMask & (1 << lir::ConstantOperand);
|
||||
}
|
||||
|
||||
virtual bool loneMatch(Context*, const SiteMask&) {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool matchNextWord(Context* c, Site* s, unsigned) {
|
||||
return s->type(c) == lir::ConstantOperand;
|
||||
}
|
||||
|
||||
virtual lir::OperandType type(Context*) {
|
||||
return lir::ConstantOperand;
|
||||
}
|
||||
|
||||
virtual void asAssemblerOperand(Context* c, Site* high,
|
||||
lir::Operand* result)
|
||||
{
|
||||
Promise* v = value;
|
||||
if (high != this) {
|
||||
v = combinedPromise(c, value, static_cast<ConstantSite*>(high)->value);
|
||||
}
|
||||
new (result) lir::Constant(v);
|
||||
}
|
||||
|
||||
virtual Site* copy(Context* c) {
|
||||
return constantSite(c, value);
|
||||
}
|
||||
|
||||
virtual Site* copyLow(Context* c) {
|
||||
return constantSite(c, shiftMaskPromise(c, value, 0, 0xFFFFFFFF));
|
||||
}
|
||||
|
||||
virtual Site* copyHigh(Context* c) {
|
||||
return constantSite(c, shiftMaskPromise(c, value, 32, 0xFFFFFFFF));
|
||||
}
|
||||
|
||||
virtual Site* makeNextWord(Context* c, unsigned) {
|
||||
abort(c);
|
||||
}
|
||||
|
||||
virtual SiteMask mask(Context*) {
|
||||
return SiteMask(1 << lir::ConstantOperand, 0, NoFrameIndex);
|
||||
}
|
||||
|
||||
virtual SiteMask nextWordMask(Context*, unsigned) {
|
||||
return SiteMask(1 << lir::ConstantOperand, 0, NoFrameIndex);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
class MemorySite: public Site {
|
||||
public:
|
||||
MemorySite(int base, int offset, int index, unsigned scale);
|
||||
|
||||
virtual unsigned toString(Context*, char* buffer, unsigned bufferSize);
|
||||
|
||||
virtual unsigned copyCost(Context* c, Site* s);
|
||||
|
||||
bool conflicts(const SiteMask& mask);
|
||||
|
||||
virtual bool match(Context* c, const SiteMask& mask);
|
||||
|
||||
virtual bool loneMatch(Context* c, const SiteMask& mask);
|
||||
|
||||
virtual bool matchNextWord(Context* c, Site* s, unsigned index);
|
||||
|
||||
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);
|
||||
|
||||
virtual lir::OperandType type(Context*);
|
||||
|
||||
virtual void asAssemblerOperand(Context* c UNUSED, Site* high UNUSED,
|
||||
lir::Operand* result);
|
||||
|
||||
virtual Site* copy(Context* c);
|
||||
|
||||
Site* copyHalf(Context* c, bool add);
|
||||
|
||||
virtual Site* copyLow(Context* c);
|
||||
|
||||
virtual Site* copyHigh(Context* c);
|
||||
|
||||
virtual Site* makeNextWord(Context* c, unsigned index);
|
||||
|
||||
virtual SiteMask mask(Context* c);
|
||||
|
||||
virtual SiteMask nextWordMask(Context* c, unsigned index);
|
||||
|
||||
virtual bool isVolatile(Context* c);
|
||||
|
||||
bool acquired;
|
||||
int base;
|
||||
int offset;
|
||||
int index;
|
||||
unsigned scale;
|
||||
};
|
||||
|
||||
MemorySite* memorySite(Context* c, int base, int offset = 0, int index = lir::NoRegister, unsigned scale = 1);
|
||||
MemorySite* frameSite(Context* c, int frameIndex);
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif // AVIAN_CODEGEN_COMPILER_SITE_H
|
164
src/codegen/compiler/value.cpp
Normal file
164
src/codegen/compiler/value.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
/* 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;
|
||||
}
|
||||
|
||||
void Value::addSite(Context* c, Site* s) {
|
||||
if (not this->findSite(s)) {
|
||||
if (DebugSites) {
|
||||
char buffer[256]; s->toString(c, buffer, 256);
|
||||
fprintf(stderr, "add site %s to %p\n", buffer, this);
|
||||
}
|
||||
s->acquire(c, this);
|
||||
s->next = this->sites;
|
||||
this->sites = s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Value::grow(Context* c) {
|
||||
assert(c, this->nextWord == this);
|
||||
|
||||
Value* next = value(c, this->type);
|
||||
this->nextWord = next;
|
||||
next->nextWord = this;
|
||||
next->wordIndex = 1;
|
||||
}
|
||||
|
||||
|
||||
void Value::maybeSplit(Context* c) {
|
||||
if (this->nextWord == this) {
|
||||
this->split(c);
|
||||
}
|
||||
}
|
||||
|
||||
void Value::split(Context* c) {
|
||||
this->grow(c);
|
||||
for (SiteIterator it(c, this); it.hasMore();) {
|
||||
Site* s = it.next();
|
||||
this->removeSite(c, s);
|
||||
|
||||
this->addSite(c, s->copyLow(c));
|
||||
this->nextWord->addSite(c, s->copyHigh(c));
|
||||
}
|
||||
}
|
||||
|
||||
void Value::removeSite(Context* c, Site* s) {
|
||||
for (SiteIterator it(c, this); it.hasMore();) {
|
||||
if (s == it.next()) {
|
||||
if (DebugSites) {
|
||||
char buffer[256]; s->toString(c, buffer, 256);
|
||||
fprintf(stderr, "remove site %s from %p\n", buffer, this);
|
||||
}
|
||||
it.remove(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (DebugSites) {
|
||||
fprintf(stderr, "%p has more: %d\n", this, this->hasSite(c));
|
||||
}
|
||||
assert(c, not this->findSite(s));
|
||||
}
|
||||
|
||||
bool Value::hasSite(Context* c) {
|
||||
SiteIterator it(c, this);
|
||||
return it.hasMore();
|
||||
}
|
||||
|
||||
bool Value::uniqueSite(Context* c, Site* s) {
|
||||
SiteIterator it(c, this);
|
||||
Site* p UNUSED = it.next();
|
||||
if (it.hasMore()) {
|
||||
// the site is not this word's only site, but if the site is
|
||||
// shared with the next word, it may be that word's only site
|
||||
if (this->nextWord != this and s->registerSize(c) > vm::TargetBytesPerWord) {
|
||||
SiteIterator nit(c, this->nextWord);
|
||||
Site* p = nit.next();
|
||||
if (nit.hasMore()) {
|
||||
return false;
|
||||
} else {
|
||||
return p == s;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
assert(c, p == s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void Value::clearSites(Context* c) {
|
||||
if (DebugSites) {
|
||||
fprintf(stderr, "clear sites for %p\n", this);
|
||||
}
|
||||
for (SiteIterator it(c, this); it.hasMore();) {
|
||||
it.next();
|
||||
it.remove(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool Value::hasBuddy(Context* c, Value* b) {
|
||||
Value* a = this;
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (Value* p = a->buddy; p != a; p = p->buddy) {
|
||||
if (p == b) {
|
||||
return true;
|
||||
}
|
||||
if (++i > 1000) {
|
||||
abort(c);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif // not NDEBUG
|
||||
|
||||
|
||||
Value* value(Context* c, lir::ValueType type, Site* site, Site* target) {
|
||||
return new(c->zone) Value(site, target, type);
|
||||
}
|
||||
|
||||
} // namespace regalloc
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
78
src/codegen/compiler/value.h
Normal file
78
src/codegen/compiler/value.h
Normal file
@ -0,0 +1,78 @@
|
||||
/* 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_VALUE_H
|
||||
#define AVIAN_CODEGEN_COMPILER_VALUE_H
|
||||
|
||||
#include "codegen/lir.h"
|
||||
|
||||
#include "codegen/compiler.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
class Read;
|
||||
class Site;
|
||||
|
||||
const int AnyFrameIndex = -2;
|
||||
const int NoFrameIndex = -1;
|
||||
|
||||
const bool DebugSites = false;
|
||||
|
||||
class Value: public Compiler::Operand {
|
||||
public:
|
||||
Read* reads;
|
||||
Read* lastRead;
|
||||
Site* sites;
|
||||
Site* source;
|
||||
Site* target;
|
||||
Value* buddy;
|
||||
Value* nextWord;
|
||||
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);
|
||||
|
||||
void addSite(Context* c, Site* s);
|
||||
|
||||
void grow(Context* c);
|
||||
|
||||
void maybeSplit(Context* c);
|
||||
|
||||
void split(Context* c);
|
||||
|
||||
void removeSite(Context* c, Site* s);
|
||||
|
||||
bool hasSite(Context* c);
|
||||
|
||||
bool uniqueSite(Context* c, Site* s);
|
||||
|
||||
void clearSites(Context* c);
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool hasBuddy(Context* c, Value* b);
|
||||
#endif // not NDEBUG
|
||||
|
||||
};
|
||||
|
||||
|
||||
Value* value(Context* c, lir::ValueType type, Site* site = 0, Site* target = 0);
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif // AVIAN_CODEGEN_COMPILER_VALUE_H
|
62
src/codegen/lir-ops.inc.cpp
Normal file
62
src/codegen/lir-ops.inc.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
LIR_OP_0(Return)
|
||||
LIR_OP_0(LoadBarrier)
|
||||
LIR_OP_0(StoreStoreBarrier)
|
||||
LIR_OP_0(StoreLoadBarrier)
|
||||
LIR_OP_0(Trap)
|
||||
|
||||
LIR_OP_1(Call)
|
||||
LIR_OP_1(LongCall)
|
||||
LIR_OP_1(AlignedLongCall)
|
||||
LIR_OP_1(AlignedCall)
|
||||
LIR_OP_1(Jump)
|
||||
LIR_OP_1(LongJump)
|
||||
LIR_OP_1(AlignedLongJump)
|
||||
LIR_OP_1(AlignedJump)
|
||||
|
||||
LIR_OP_2(Move)
|
||||
LIR_OP_2(MoveLow)
|
||||
LIR_OP_2(MoveHigh)
|
||||
LIR_OP_2(MoveZ)
|
||||
LIR_OP_2(Negate)
|
||||
LIR_OP_2(FloatNegate)
|
||||
LIR_OP_2(Float2Float)
|
||||
LIR_OP_2(Float2Int)
|
||||
LIR_OP_2(Int2Float)
|
||||
LIR_OP_2(FloatSquareRoot)
|
||||
LIR_OP_2(FloatAbsolute)
|
||||
LIR_OP_2(Absolute)
|
||||
|
||||
LIR_OP_3(Add)
|
||||
LIR_OP_3(Subtract)
|
||||
LIR_OP_3(Multiply)
|
||||
LIR_OP_3(Divide)
|
||||
LIR_OP_3(Remainder)
|
||||
LIR_OP_3(ShiftLeft)
|
||||
LIR_OP_3(ShiftRight)
|
||||
LIR_OP_3(UnsignedShiftRight)
|
||||
LIR_OP_3(And)
|
||||
LIR_OP_3(Or)
|
||||
LIR_OP_3(Xor)
|
||||
LIR_OP_3(FloatAdd)
|
||||
LIR_OP_3(FloatSubtract)
|
||||
LIR_OP_3(FloatMultiply)
|
||||
LIR_OP_3(FloatDivide)
|
||||
LIR_OP_3(FloatRemainder)
|
||||
LIR_OP_3(FloatMax)
|
||||
LIR_OP_3(FloatMin)
|
||||
LIR_OP_3(JumpIfLess)
|
||||
LIR_OP_3(JumpIfGreater)
|
||||
LIR_OP_3(JumpIfLessOrEqual)
|
||||
LIR_OP_3(JumpIfGreaterOrEqual)
|
||||
LIR_OP_3(JumpIfEqual)
|
||||
LIR_OP_3(JumpIfNotEqual)
|
||||
LIR_OP_3(JumpIfFloatEqual)
|
||||
LIR_OP_3(JumpIfFloatNotEqual)
|
||||
LIR_OP_3(JumpIfFloatLess)
|
||||
LIR_OP_3(JumpIfFloatGreater)
|
||||
LIR_OP_3(JumpIfFloatLessOrEqual)
|
||||
LIR_OP_3(JumpIfFloatGreaterOrEqual)
|
||||
LIR_OP_3(JumpIfFloatLessOrUnordered)
|
||||
LIR_OP_3(JumpIfFloatGreaterOrUnordered)
|
||||
LIR_OP_3(JumpIfFloatLessOrEqualOrUnordered)
|
||||
LIR_OP_3(JumpIfFloatGreaterOrEqualOrUnordered)
|
35
src/codegen/lir.cpp
Normal file
35
src/codegen/lir.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
/* 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 "lir.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const char* lirOpcodeNames[] = {
|
||||
#define LIR_OP_0(x) #x
|
||||
#define LIR_OP_1(x) #x
|
||||
#define LIR_OP_2(x) #x
|
||||
#define LIR_OP_3(x) #x
|
||||
#include "lir-ops.inc.cpp"
|
||||
#undef LIR_OP_0
|
||||
#undef LIR_OP_1
|
||||
#undef LIR_OP_2
|
||||
#undef LIR_OP_3
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace vm {
|
||||
|
||||
const char* LirInstr::opcodeName(Opcode op) {
|
||||
return lirOpcodeNames[op];
|
||||
}
|
||||
|
||||
}
|
174
src/codegen/lir.h
Normal file
174
src/codegen/lir.h
Normal file
@ -0,0 +1,174 @@
|
||||
/* 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_LIR_H
|
||||
#define AVIAN_CODEGEN_LIR_H
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
class Promise;
|
||||
|
||||
namespace lir {
|
||||
enum Operation {
|
||||
#define LIR_OP_0(x) x,
|
||||
#define LIR_OP_1(x)
|
||||
#define LIR_OP_2(x)
|
||||
#define LIR_OP_3(x)
|
||||
#include "lir-ops.inc.cpp"
|
||||
#undef LIR_OP_0
|
||||
#undef LIR_OP_1
|
||||
#undef LIR_OP_2
|
||||
#undef LIR_OP_3
|
||||
};
|
||||
|
||||
const unsigned OperationCount = Trap + 1;
|
||||
|
||||
enum UnaryOperation {
|
||||
#define LIR_OP_0(x)
|
||||
#define LIR_OP_1(x) x,
|
||||
#define LIR_OP_2(x)
|
||||
#define LIR_OP_3(x)
|
||||
#include "lir-ops.inc.cpp"
|
||||
#undef LIR_OP_0
|
||||
#undef LIR_OP_1
|
||||
#undef LIR_OP_2
|
||||
#undef LIR_OP_3
|
||||
|
||||
NoUnaryOperation = -1
|
||||
};
|
||||
|
||||
const unsigned UnaryOperationCount = AlignedJump + 1;
|
||||
|
||||
enum BinaryOperation {
|
||||
#define LIR_OP_0(x)
|
||||
#define LIR_OP_1(x)
|
||||
#define LIR_OP_2(x) x,
|
||||
#define LIR_OP_3(x)
|
||||
#include "lir-ops.inc.cpp"
|
||||
#undef LIR_OP_0
|
||||
#undef LIR_OP_1
|
||||
#undef LIR_OP_2
|
||||
#undef LIR_OP_3
|
||||
|
||||
NoBinaryOperation = -1
|
||||
};
|
||||
|
||||
const unsigned BinaryOperationCount = Absolute + 1;
|
||||
|
||||
enum TernaryOperation {
|
||||
#define LIR_OP_0(x)
|
||||
#define LIR_OP_1(x)
|
||||
#define LIR_OP_2(x)
|
||||
#define LIR_OP_3(x) x,
|
||||
#include "lir-ops.inc.cpp"
|
||||
#undef LIR_OP_0
|
||||
#undef LIR_OP_1
|
||||
#undef LIR_OP_2
|
||||
#undef LIR_OP_3
|
||||
|
||||
NoTernaryOperation = -1
|
||||
};
|
||||
|
||||
const unsigned TernaryOperationCount
|
||||
= JumpIfFloatGreaterOrEqualOrUnordered + 1;
|
||||
|
||||
const unsigned NonBranchTernaryOperationCount = FloatMin + 1;
|
||||
const unsigned BranchOperationCount
|
||||
= JumpIfFloatGreaterOrEqualOrUnordered - FloatMin;
|
||||
|
||||
enum OperandType {
|
||||
ConstantOperand,
|
||||
AddressOperand,
|
||||
RegisterOperand,
|
||||
MemoryOperand
|
||||
};
|
||||
|
||||
enum ValueType {
|
||||
ValueGeneral,
|
||||
ValueFloat
|
||||
};
|
||||
|
||||
const unsigned OperandTypeCount = MemoryOperand + 1;
|
||||
|
||||
const int NoRegister = -1;
|
||||
|
||||
|
||||
inline bool isBranch(lir::TernaryOperation op) {
|
||||
return op > FloatMin;
|
||||
}
|
||||
|
||||
inline bool isFloatBranch(lir::TernaryOperation op) {
|
||||
return op > JumpIfNotEqual;
|
||||
}
|
||||
|
||||
class Operand { };
|
||||
|
||||
class Constant: public Operand {
|
||||
public:
|
||||
Constant(Promise* value): value(value) { }
|
||||
|
||||
Promise* value;
|
||||
};
|
||||
|
||||
class Address: public Operand {
|
||||
public:
|
||||
Address(Promise* address): address(address) { }
|
||||
|
||||
Promise* address;
|
||||
};
|
||||
|
||||
class Register: public Operand {
|
||||
public:
|
||||
Register(int low, int high = NoRegister): low(low), high(high) { }
|
||||
|
||||
int low;
|
||||
int high;
|
||||
};
|
||||
|
||||
class Memory: public Operand {
|
||||
public:
|
||||
Memory(int base, int offset, int index = NoRegister, unsigned scale = 1):
|
||||
base(base), offset(offset), index(index), scale(scale)
|
||||
{ }
|
||||
|
||||
int base;
|
||||
int offset;
|
||||
int index;
|
||||
unsigned scale;
|
||||
};
|
||||
|
||||
class Instr {
|
||||
public:
|
||||
|
||||
enum Opcode {
|
||||
#define LIR_OP_0(x) OP_##x,
|
||||
#define LIR_OP_1(x) OP_##x,
|
||||
#define LIR_OP_2(x) OP_##x,
|
||||
#define LIR_OP_3(x) OP_##x,
|
||||
#include "lir-ops.inc.cpp"
|
||||
#undef LIR_OP_0
|
||||
#undef LIR_OP_1
|
||||
#undef LIR_OP_2
|
||||
#undef LIR_OP_3
|
||||
};
|
||||
|
||||
static const char* opcodeName(Opcode op);
|
||||
|
||||
static Opcode opcodeFromNullary(Operation op);
|
||||
static Opcode opcodeFromUnary(UnaryOperation op);
|
||||
static Opcode opcodeFromBinary(BinaryOperation op);
|
||||
static Opcode opcodeFromTernary(TernaryOperation op);
|
||||
};
|
||||
|
||||
} // namespace lir
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif // AVIAN_CODEGEN_LIR_H
|
File diff suppressed because it is too large
Load Diff
159
src/codegen/promise.h
Normal file
159
src/codegen/promise.h
Normal file
@ -0,0 +1,159 @@
|
||||
/* 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_PROMISE_H
|
||||
#define AVIAN_CODEGEN_PROMISE_H
|
||||
|
||||
#include "allocator.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
|
||||
class Promise {
|
||||
public:
|
||||
class Listener {
|
||||
public:
|
||||
virtual bool resolve(int64_t value, void** location) = 0;
|
||||
|
||||
Listener* next;
|
||||
};
|
||||
|
||||
virtual int64_t value() = 0;
|
||||
virtual bool resolved() = 0;
|
||||
virtual Listener* listen(unsigned) { return 0; }
|
||||
};
|
||||
|
||||
class ResolvedPromise: public Promise {
|
||||
public:
|
||||
ResolvedPromise(int64_t value): value_(value) { }
|
||||
|
||||
virtual int64_t value() {
|
||||
return value_;
|
||||
}
|
||||
|
||||
virtual bool resolved() {
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t value_;
|
||||
};
|
||||
|
||||
class ShiftMaskPromise: public Promise {
|
||||
public:
|
||||
ShiftMaskPromise(Promise* base, unsigned shift, int64_t mask):
|
||||
base(base), shift(shift), mask(mask)
|
||||
{ }
|
||||
|
||||
virtual int64_t value() {
|
||||
return (base->value() >> shift) & mask;
|
||||
}
|
||||
|
||||
virtual bool resolved() {
|
||||
return base->resolved();
|
||||
}
|
||||
|
||||
Promise* base;
|
||||
unsigned shift;
|
||||
int64_t mask;
|
||||
};
|
||||
|
||||
class CombinedPromise: public Promise {
|
||||
public:
|
||||
CombinedPromise(Promise* low, Promise* high):
|
||||
low(low), high(high)
|
||||
{ }
|
||||
|
||||
virtual int64_t value() {
|
||||
return low->value() | (high->value() << 32);
|
||||
}
|
||||
|
||||
virtual bool resolved() {
|
||||
return low->resolved() and high->resolved();
|
||||
}
|
||||
|
||||
Promise* low;
|
||||
Promise* high;
|
||||
};
|
||||
|
||||
class OffsetPromise: public Promise {
|
||||
public:
|
||||
OffsetPromise(Promise* base, int64_t offset):
|
||||
base(base), offset(offset)
|
||||
{ }
|
||||
|
||||
virtual int64_t value() {
|
||||
return base->value() + offset;
|
||||
}
|
||||
|
||||
virtual bool resolved() {
|
||||
return base->resolved();
|
||||
}
|
||||
|
||||
Promise* base;
|
||||
int64_t offset;
|
||||
};
|
||||
|
||||
class ListenPromise: public Promise {
|
||||
public:
|
||||
ListenPromise(vm::System* s, vm::Allocator* allocator):
|
||||
s(s), allocator(allocator), listener(0)
|
||||
{ }
|
||||
|
||||
virtual int64_t value() {
|
||||
abort(s);
|
||||
}
|
||||
|
||||
virtual bool resolved() {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual Listener* listen(unsigned sizeInBytes) {
|
||||
Listener* l = static_cast<Listener*>(allocator->allocate(sizeInBytes));
|
||||
l->next = listener;
|
||||
listener = l;
|
||||
return l;
|
||||
}
|
||||
|
||||
vm::System* s;
|
||||
vm::Allocator* allocator;
|
||||
Listener* listener;
|
||||
Promise* promise;
|
||||
};
|
||||
|
||||
class DelayedPromise: public ListenPromise {
|
||||
public:
|
||||
DelayedPromise(vm::System* s, vm::Allocator* allocator, Promise* basis,
|
||||
DelayedPromise* next):
|
||||
ListenPromise(s, allocator), basis(basis), next(next)
|
||||
{ }
|
||||
|
||||
virtual int64_t value() {
|
||||
abort(s);
|
||||
}
|
||||
|
||||
virtual bool resolved() {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual Listener* listen(unsigned sizeInBytes) {
|
||||
Listener* l = static_cast<Listener*>(allocator->allocate(sizeInBytes));
|
||||
l->next = listener;
|
||||
listener = l;
|
||||
return l;
|
||||
}
|
||||
|
||||
Promise* basis;
|
||||
DelayedPromise* next;
|
||||
};
|
||||
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif // AVIAN_CODEGEN_PROMISE_H
|
35
src/codegen/registers.cpp
Normal file
35
src/codegen/registers.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
/* 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/registers.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
|
||||
unsigned
|
||||
RegisterMask::maskStart(uint32_t mask)
|
||||
{
|
||||
for (int i = 0; i <= 31; ++i) {
|
||||
if (mask & (1 << i)) return i;
|
||||
}
|
||||
return 32;
|
||||
}
|
||||
|
||||
unsigned
|
||||
RegisterMask::maskLimit(uint32_t mask)
|
||||
{
|
||||
for (int i = 31; i >= 0; --i) {
|
||||
if (mask & (1 << i)) return i + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
51
src/codegen/registers.h
Normal file
51
src/codegen/registers.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* 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_REGISTERS_H
|
||||
#define AVIAN_CODEGEN_REGISTERS_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
|
||||
class RegisterMask {
|
||||
public:
|
||||
uint32_t mask;
|
||||
uint8_t start;
|
||||
uint8_t limit;
|
||||
|
||||
static unsigned maskStart(uint32_t mask);
|
||||
static unsigned maskLimit(uint32_t mask);
|
||||
|
||||
inline RegisterMask(uint32_t mask):
|
||||
mask(mask),
|
||||
start(maskStart(mask)),
|
||||
limit(maskLimit(mask))
|
||||
{ }
|
||||
};
|
||||
|
||||
class RegisterFile {
|
||||
public:
|
||||
RegisterMask allRegisters;
|
||||
RegisterMask generalRegisters;
|
||||
RegisterMask floatRegisters;
|
||||
|
||||
inline RegisterFile(uint32_t generalRegisterMask, uint32_t floatRegisterMask):
|
||||
allRegisters(generalRegisterMask | floatRegisterMask),
|
||||
generalRegisters(generalRegisterMask),
|
||||
floatRegisters(floatRegisterMask)
|
||||
{ }
|
||||
};
|
||||
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
||||
#endif // AVIAN_CODEGEN_REGISTERS_H
|
@ -14,7 +14,7 @@
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
|
||||
vm::Assembler::Architecture* makeArchitectureNative(vm::System* system, bool useNativeFeatures UNUSED) {
|
||||
Assembler::Architecture* makeArchitectureNative(vm::System* system, bool useNativeFeatures UNUSED) {
|
||||
#ifndef AVIAN_TARGET_ARCH
|
||||
#error "Must specify native target!"
|
||||
#endif
|
||||
|
@ -16,11 +16,11 @@
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
|
||||
vm::Assembler::Architecture* makeArchitectureNative(vm::System* system, bool useNativeFeatures);
|
||||
Assembler::Architecture* makeArchitectureNative(vm::System* system, bool useNativeFeatures);
|
||||
|
||||
vm::Assembler::Architecture* makeArchitectureX86(vm::System* system, bool useNativeFeatures);
|
||||
vm::Assembler::Architecture* makeArchitectureArm(vm::System* system, bool useNativeFeatures);
|
||||
vm::Assembler::Architecture* makeArchitecturePowerpc(vm::System* system, bool useNativeFeatures);
|
||||
Assembler::Architecture* makeArchitectureX86(vm::System* system, bool useNativeFeatures);
|
||||
Assembler::Architecture* makeArchitectureArm(vm::System* system, bool useNativeFeatures);
|
||||
Assembler::Architecture* makeArchitecturePowerpc(vm::System* system, bool useNativeFeatures);
|
||||
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
File diff suppressed because it is too large
Load Diff
416
src/compile.cpp
416
src/compile.cpp
File diff suppressed because it is too large
Load Diff
19
src/heap.cpp
19
src/heap.cpp
@ -55,10 +55,7 @@ class MutexLock {
|
||||
|
||||
class Context;
|
||||
|
||||
void NO_RETURN abort(Context*);
|
||||
#ifndef NDEBUG
|
||||
void assert(Context*, bool);
|
||||
#endif
|
||||
Aborter* getAborter(Context* c);
|
||||
|
||||
void* tryAllocate(Context* c, unsigned size);
|
||||
void* allocate(Context* c, unsigned size);
|
||||
@ -745,20 +742,10 @@ segment(Context* c, void* p)
|
||||
}
|
||||
}
|
||||
|
||||
inline void NO_RETURN
|
||||
abort(Context* c)
|
||||
{
|
||||
abort(c->system);
|
||||
inline Aborter* getAborter(Context* c) {
|
||||
return c->system;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
inline void
|
||||
assert(Context* c, bool v)
|
||||
{
|
||||
assert(c->system, v);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline unsigned
|
||||
minimumNextGen1Capacity(Context* c)
|
||||
{
|
||||
|
@ -3966,7 +3966,7 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size,
|
||||
Client(Thread* t): t(t) { }
|
||||
|
||||
virtual void NO_RETURN handleError() {
|
||||
vm::abort(t);
|
||||
abort(t);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -4853,11 +4853,11 @@ makeTrace(Thread* t, Processor::StackWalker* walker)
|
||||
virtual bool visit(Processor::StackWalker* walker) {
|
||||
if (trace == 0) {
|
||||
trace = makeObjectArray(t, walker->count());
|
||||
vm_assert(t, trace);
|
||||
assert(t, trace);
|
||||
}
|
||||
|
||||
object e = makeTraceElement(t, walker->method(), walker->ip());
|
||||
vm_assert(t, index < objectArrayLength(t, trace));
|
||||
assert(t, index < objectArrayLength(t, trace));
|
||||
set(t, trace, ArrayBody + (index * BytesPerWord), e);
|
||||
++ index;
|
||||
return true;
|
||||
|
@ -1761,24 +1761,8 @@ class RawMonitorResource: public Thread::Resource {
|
||||
System::Monitor* m;
|
||||
};
|
||||
|
||||
inline void NO_RETURN
|
||||
abort(Thread* t)
|
||||
{
|
||||
abort(t->m->system);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
inline void
|
||||
assert(Thread* t, bool v)
|
||||
{
|
||||
assert(t->m->system, v);
|
||||
}
|
||||
#endif // not NDEBUG
|
||||
|
||||
inline void
|
||||
expect(Thread* t, bool v)
|
||||
{
|
||||
expect(t->m->system, v);
|
||||
inline Aborter* getAborter(Thread* t) {
|
||||
return t->m->system;
|
||||
}
|
||||
|
||||
class FixedAllocator: public Allocator {
|
||||
|
@ -18,9 +18,13 @@
|
||||
#include "heapwalk.h"
|
||||
#include "zone.h"
|
||||
|
||||
namespace vm {
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
class DelayedPromise;
|
||||
}
|
||||
}
|
||||
|
||||
namespace vm {
|
||||
|
||||
class Processor {
|
||||
public:
|
||||
@ -143,7 +147,7 @@ class Processor {
|
||||
|
||||
virtual void
|
||||
compileMethod(Thread* t, Zone* zone, object* constants, object* calls,
|
||||
DelayedPromise** addresses, object method,
|
||||
avian::codegen::DelayedPromise** addresses, object method,
|
||||
OffsetResolver* resolver) = 0;
|
||||
|
||||
virtual void
|
||||
|
39
src/system.h
39
src/system.h
@ -13,10 +13,11 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "allocator.h"
|
||||
#include "util/abort.h"
|
||||
|
||||
namespace vm {
|
||||
|
||||
class System {
|
||||
class System : public Aborter {
|
||||
public:
|
||||
typedef intptr_t Status;
|
||||
|
||||
@ -150,7 +151,6 @@ class System {
|
||||
virtual int64_t now() = 0;
|
||||
virtual void yield() = 0;
|
||||
virtual void exit(int code) = 0;
|
||||
virtual void abort() = 0;
|
||||
virtual void dispose() = 0;
|
||||
};
|
||||
|
||||
@ -165,11 +165,8 @@ allocate(System* s, unsigned size)
|
||||
#define ACQUIRE_MONITOR(t, m) \
|
||||
System::MonitorResource MAKE_NAME(monitorResource_) (t, m)
|
||||
|
||||
inline void NO_RETURN
|
||||
abort(System* s)
|
||||
{
|
||||
s->abort(); // this should not return
|
||||
::abort();
|
||||
inline Aborter* getAborter(System* s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
inline void NO_RETURN
|
||||
@ -178,28 +175,22 @@ sysAbort(System* s)
|
||||
abort(s);
|
||||
}
|
||||
|
||||
inline void
|
||||
expect(System* s, bool v)
|
||||
{
|
||||
if (UNLIKELY(not v)) abort(s);
|
||||
}
|
||||
// #ifdef NDEBUG
|
||||
|
||||
#ifdef NDEBUG
|
||||
// # define assert(a, b)
|
||||
// # define vm_assert(a, b)
|
||||
|
||||
# define assert(a, b)
|
||||
# define vm_assert(a, b)
|
||||
// #else // not NDEBUG
|
||||
|
||||
#else // not NDEBUG
|
||||
// inline void
|
||||
// assert(System* s, bool v)
|
||||
// {
|
||||
// expect(s, v);
|
||||
// }
|
||||
|
||||
inline void
|
||||
assert(System* s, bool v)
|
||||
{
|
||||
expect(s, v);
|
||||
}
|
||||
// # define vm_assert(a, b) vm::assert(a, b)
|
||||
|
||||
# define vm_assert(a, b) vm::assert(a, b)
|
||||
|
||||
#endif // not NDEBUG
|
||||
// #endif // not NDEBUG
|
||||
|
||||
JNIEXPORT System*
|
||||
makeSystem(const char* crashDumpDirectory);
|
||||
|
41
src/util/abort.h
Normal file
41
src/util/abort.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* 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_UTIL_ABORT_H
|
||||
#define AVIAN_UTIL_ABORT_H
|
||||
|
||||
class Aborter {
|
||||
public:
|
||||
virtual void NO_RETURN abort() = 0;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
inline void NO_RETURN abort(T t) {
|
||||
getAborter(t)->abort();
|
||||
::abort();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void expect(T t, bool v) {
|
||||
if(UNLIKELY(!v)) {
|
||||
abort(t);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define assert(t, v)
|
||||
#else
|
||||
template<class T>
|
||||
inline void assert(T t, bool v) {
|
||||
expect(t, v);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // AVIAN_UTIL_ABORT_H
|
@ -8,8 +8,8 @@
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
#ifndef UTIL_RUNTIME_ARRAY_H
|
||||
#define UTIL_RUNTIME_ARRAY_H
|
||||
#ifndef AVIAN_UTIL_RUNTIME_ARRAY_H
|
||||
#define AVIAN_UTIL_RUNTIME_ARRAY_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
@ -37,4 +37,4 @@ class RuntimeArray {
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif // AVIAN_UTIL_RUNTIME_ARRAY_H
|
Loading…
Reference in New Issue
Block a user