Bug 490947 - nanojit: remove reservation table. r=gal,edwsmith

This commit is contained in:
Nicholas Nethercote 2009-05-18 02:15:24 -04:00
parent 6c4c7621f3
commit 90746fda0d
7 changed files with 73 additions and 162 deletions

View File

@ -71,7 +71,7 @@ namespace nanojit
ins->isRet()) {
return false;
}
return ins->resv() == 0;
return !ins->resv()->used;
}
public:
@ -220,6 +220,7 @@ namespace nanojit
NanoAssert(vic != NULL);
Reservation* resv = getresv(vic);
NanoAssert(resv);
// restore vic
Register r = resv->reg;
@ -230,17 +231,6 @@ namespace nanojit
return r;
}
void Assembler::reserveReset()
{
_resvTable[0].arIndex = 0;
int i;
for(i=1; i<NJ_MAX_STACK_ENTRY; i++) {
_resvTable[i].arIndex = i-1;
_resvTable[i].used = 0;
}
_resvFree= i-1;
}
/**
* these instructions don't have to be saved & reloaded to spill,
* they can just be recalculated w/out any inputs.
@ -249,41 +239,10 @@ namespace nanojit
return i->isconst() || i->isconstq() || i->isop(LIR_alloc);
}
Reservation* Assembler::reserveAlloc(LInsp i)
{
uint32_t item = _resvFree;
/* If there are no free reservations, mark the table as full and re-use an index.
* This will clobber that reservation, but the error will be caught as soon as
* the current LIR instruction returns back to gen().
*/
if (!item) {
setError(ResvFull);
item = 1;
}
Reservation *r = &_resvTable[item];
_resvFree = r->arIndex;
r->reg = UnknownReg;
r->arIndex = 0;
r->used = 1;
i->setresv(item);
return r;
}
void Assembler::reserveFree(LInsp i)
{
Reservation *rs = getresv(i);
NanoAssert(rs == &_resvTable[i->resv()]);
rs->arIndex = _resvFree;
rs->used = 0;
_resvFree = i->resv();
i->setresv(0);
}
void Assembler::internalReset()
{
// readies for a brand spanking new code generation pass.
registerResetAll();
reserveReset();
arReset();
pending_lives.clear();
}
@ -426,8 +385,6 @@ namespace nanojit
continue;
Reservation *r = getresv(ins);
NanoAssert(r != 0);
int32_t idx = r - _resvTable;
NanoAssertMsg(idx, "MUST have a resource for the instruction for it to have a stack location assigned to it");
if (r->arIndex) {
if (ins->isop(LIR_alloc)) {
int j=i+1;
@ -449,21 +406,6 @@ namespace nanojit
}
registerConsistencyCheck();
// check resv table
int32_t inuseCount = 0;
int32_t notInuseCount = 0;
for(uint32_t i=1; i < sizeof(_resvTable)/sizeof(_resvTable[0]); i++) {
_resvTable[i].used ? inuseCount++ : notInuseCount++;
}
int32_t freeCount = 0;
uint32_t free = _resvFree;
while(free) {
free = _resvTable[free].arIndex;
freeCount++;
}
NanoAssert( ( freeCount==notInuseCount && inuseCount+notInuseCount==(NJ_MAX_STACK_ENTRY-1) ) );
}
void Assembler::registerConsistencyCheck()
@ -486,9 +428,6 @@ namespace nanojit
// @todo we should be able to check across RegAlloc's somehow (to include savedGP...)
Reservation *v = getresv(ins);
NanoAssert(v != 0);
int32_t idx = v - _resvTable;
NanoAssert(idx >= 0 && idx < NJ_MAX_STACK_ENTRY);
NanoAssertMsg(idx, "MUST have a resource for the instruction for it to have a register assigned to it");
NanoAssertMsg( regs->getActive(v->reg)==ins, "Register record mismatch");
}
}
@ -570,7 +509,7 @@ namespace nanojit
// if we didn't have a reservation, allocate one now
if (!resv)
resv = reserveAlloc(i);
resv = i->initResv();
r = resv->reg;
@ -619,7 +558,7 @@ namespace nanojit
{
Reservation* resv = getresv(i);
if (!resv)
resv = reserveAlloc(i);
resv = i->initResv();
if (!resv->arIndex) {
resv->arIndex = arReserve(i);
NanoAssert(resv->arIndex <= _activation.highwatermark);
@ -658,7 +597,7 @@ namespace nanojit
}
if (index)
arFree(index); // free any stack stack space associated with entry
reserveFree(i); // clear fields of entry and add it to free list
i->clearResv();
}
void Assembler::evict(Register r)
@ -1007,7 +946,7 @@ namespace nanojit
if (!resv->arIndex && resv->reg == UnknownReg)
{
reserveFree(i);
i->clearResv();
}
}
}

View File

@ -46,10 +46,6 @@ namespace nanojit
/**
* Some notes on this Assembler (Emitter).
*
* LIR_call is a generic call operation that is encoded using form [2]. The 24bit
* integer is used as an index into a function look-up table that contains information
* about the target that is to be called; including address, # parameters, etc.
*
* The class RegAlloc is essentially the register allocator from MIR
*
* The Assembler class parses the LIR instructions starting at any point and converts
@ -67,16 +63,6 @@ namespace nanojit
#define STACK_GRANULARITY sizeof(void *)
/**
* The Assembler is only concerned with transforming LIR to native instructions
*/
struct Reservation
{
uint32_t arIndex:16; /* index into stack frame. displ is -4*arIndex */
Register reg:15; /* register UnkownReg implies not in register */
uint32_t used:1;
};
struct AR
{
LIns* entry[ NJ_MAX_STACK_ENTRY ]; /* maps to 4B contiguous locations relative to the frame pointer */
@ -118,7 +104,6 @@ namespace nanojit
None = 0
,OutOMem
,StackFull
,ResvFull
,RegionFull
,MaxLength
,MaxExit
@ -247,13 +232,9 @@ namespace nanojit
void internalReset();
bool canRemat(LIns*);
Reservation* reserveAlloc(LInsp i);
void reserveFree(LInsp i);
void reserveReset();
Reservation* getresv(LIns *x) {
uint32_t resv_index = x->resv();
return resv_index ? &_resvTable[resv_index] : 0;
Reservation* r = x->resv();
return r->used ? r : 0;
}
DWB(Fragmento*) _frago;
@ -274,8 +255,6 @@ namespace nanojit
LabelStateMap _labels;
NInsMap _patches;
Reservation _resvTable[ NJ_MAX_STACK_ENTRY ]; // table where we house stack and register information
uint32_t _resvFree;
bool _inExit, vpad2[3];
InsList pending_lives;

View File

@ -367,7 +367,7 @@ namespace nanojit
}
bool LIns::isFloat() const {
switch (u.code) {
switch (firstWord.code) {
default:
return false;
case LIR_fadd:
@ -384,22 +384,22 @@ namespace nanojit
}
bool LIns::isCmp() const {
LOpcode op = u.code;
LOpcode op = firstWord.code;
return (op >= LIR_eq && op <= LIR_uge) || (op >= LIR_feq && op <= LIR_fge);
}
bool LIns::isCond() const {
LOpcode op = u.code;
LOpcode op = firstWord.code;
return (op == LIR_ov) || (op == LIR_cs) || isCmp();
}
bool LIns::isQuad() const {
#ifdef AVMPLUS_64BIT
// callh in 64bit cpu's means a call that returns an int64 in a single register
return (u.code & LIR64) != 0 || u.code == LIR_callh;
return (firstWord.code & LIR64) != 0 || firstWord.code == LIR_callh;
#else
// callh in 32bit cpu's means the 32bit MSW of an int64 result in 2 registers
return (u.code & LIR64) != 0;
return (firstWord.code & LIR64) != 0;
#endif
}
@ -410,7 +410,7 @@ namespace nanojit
bool LIns::isconstq() const
{
return u.code == LIR_quad;
return firstWord.code == LIR_quad;
}
bool LIns::isconstp() const
@ -424,14 +424,27 @@ namespace nanojit
bool LIns::isCse(const CallInfo *functions) const
{
return nanojit::isCseOpcode(u.code) || (isCall() && callInfo()->_cse);
return nanojit::isCseOpcode(firstWord.code) || (isCall() && callInfo()->_cse);
}
void LIns::initOpcodeAndClearResv(LOpcode op)
{
NanoAssert(4*sizeof(void*) == sizeof(LIns));
u.code = op;
u.resv = 0; // have to zero this; the Assembler relies on it
firstWord.code = op;
firstWord.used = 0;
}
Reservation* LIns::initResv()
{
firstWord.reg = UnknownReg;
firstWord.arIndex = 0;
firstWord.used = 1;
return &firstWord;
}
void LIns::clearResv()
{
firstWord.used = 0;
}
void LIns::setTarget(LInsp label)
@ -894,7 +907,7 @@ namespace nanojit
// N+4 arg operand #2 ----------------------
// N+8 arg operand #1 ----------------------
// N+12 arg operand #0 ---------------------- ]
// N+16 [ code=LIR_call | resv | (pad16) ------ K+1
// N+16 [ arIndex | reg | used | code=LIR_call K+1
// imm8a | (pad24) ---------------------
// imm8b | (pad24) ---------------------
// ci ---------------------------------- ]

View File

@ -161,56 +161,53 @@ namespace nanojit
#define _sign_int int32_t
#endif
// Low-level Instruction. 4 words per instruction.
// had to lay it our as a union with duplicate code fields since msvc couldn't figure out how to compact it otherwise.
// The opcode is not logically part of the Reservation, but we include it
// in this struct to ensure that opcode plus the Reservation fits in a
// single word. Yuk.
struct Reservation
{
uint32_t arIndex:16; // index into stack frame. displ is -4*arIndex
Register reg:7; // register UnknownReg implies not in register
uint32_t used:1; // when set, the reservation is active
LOpcode code:8;
};
// Low-level Instruction. 4 words per instruction -- it's important this
// doesn't change unintentionally, so it is checked in LIR.cpp by an
// assertion in initOpcodeAndClearResv().
// The first word is the same for all LIns kinds; the last three differ.
class LIns
{
#define LI_BITS_PER_WORD (8 * sizeof(void*))
friend class LirBufWriter;
// 2-operand form. Also used for LIR_skip (for which oprnd_1 is the target).
// 2-operand form. Used for most LIns kinds, including LIR_skip (for
// which oprnd_1 is the target).
struct u_type
{
LOpcode code:8;
uintptr_t resv:8; // clobbered during assembly
uintptr_t unused1:(LI_BITS_PER_WORD - 16);
// Nb: oprnd_1 and oprnd_2 layout must match that in sti_type.
// Nb: oprnd_1 and oprnd_2 layout must match that in sti_type
// because oprnd1() and oprnd2() are used for both.
LIns* oprnd_1;
LIns* oprnd_2;
uintptr_t unused4;
};
// Used for LIR_sti and LIR_stqi.
struct sti_type
{
LOpcode code:8;
uintptr_t resv:8; // clobbered during assembly
uintptr_t :(LI_BITS_PER_WORD - 16);
// Nb: oprnd_1 and oprnd_2 layout must match that in u_type.
// Nb: oprnd_1 and oprnd_2 layout must match that in u_type
// because oprnd1() and oprnd2() are used for both.
LIns* oprnd_1;
LIns* oprnd_2;
int32_t disp;
uintptr_t :(LI_BITS_PER_WORD - 32);
};
// Used for LIR_call and LIR_param.
struct c_type
{
LOpcode code:8;
uintptr_t resv:8; // clobbered during assembly
uintptr_t :(LI_BITS_PER_WORD - 16);
uintptr_t imm8a:8; // call: 0 (not used); param: arg
uintptr_t :(LI_BITS_PER_WORD - 8);
uintptr_t imm8b:8; // call: argc; param: kind
uintptr_t :(LI_BITS_PER_WORD - 8);
const CallInfo* ci; // call: callInfo; param: NULL (not used)
};
@ -218,37 +215,23 @@ namespace nanojit
// Used for LIR_int.
struct i_type
{
LOpcode code:8;
uintptr_t resv:8; // clobbered during assembly
uintptr_t :(LI_BITS_PER_WORD - 16);
int32_t imm32;
uintptr_t :(LI_BITS_PER_WORD - 32);
uintptr_t unused3;
uintptr_t unused4;
};
// Used for LIR_quad.
struct i64_type
{
LOpcode code:8;
uintptr_t resv:8; // clobbered during assembly
uintptr_t unused1:(LI_BITS_PER_WORD - 16);
int32_t imm64_0;
uintptr_t :(LI_BITS_PER_WORD - 32);
int32_t imm64_1;
uintptr_t :(LI_BITS_PER_WORD - 32);
uintptr_t unused4;
};
#undef _sign_int
// Various forms of the instruction.
// 1st word: fields shared by all LIns kinds. The reservation fields
// are read/written during assembly.
Reservation firstWord;
// 2nd, 3rd and 4th words: differ depending on the LIns kind.
union
{
u_type u;
@ -262,7 +245,7 @@ namespace nanojit
LIns* oprnd1() const { return u.oprnd_1; }
LIns* oprnd2() const { return u.oprnd_2; }
inline LOpcode opcode() const { return u.code; }
inline LOpcode opcode() const { return firstWord.code; }
inline uint8_t imm8() const { return c.imm8a; }
inline uint8_t imm8b() const { return c.imm8b; }
inline int32_t imm32() const { NanoAssert(isconst()); return i.imm32; }
@ -270,7 +253,7 @@ namespace nanojit
inline int32_t imm64_1() const { NanoAssert(isconstq()); return i64.imm64_1; }
uint64_t imm64() const;
double imm64f() const;
inline uint8_t resv() const { return u.resv; }
Reservation* resv() { return &firstWord; }
void* payload() const;
inline Page* page() { return (Page*) alignTo(this,NJ_PAGE_SIZE); }
inline int32_t size() const {
@ -300,32 +283,32 @@ namespace nanojit
}
bool isCse(const CallInfo *functions) const;
bool isRet() const { return nanojit::isRetOpcode(u.code); }
bool isop(LOpcode o) const { return u.code == o; }
bool isRet() const { return nanojit::isRetOpcode(firstWord.code); }
bool isop(LOpcode o) const { return firstWord.code == o; }
bool isQuad() const;
bool isCond() const;
bool isFloat() const;
bool isCmp() const;
bool isCall() const {
LOpcode op = LOpcode(u.code & ~LIR64);
LOpcode op = LOpcode(firstWord.code & ~LIR64);
return op == LIR_call || op == LIR_calli;
}
bool isStore() const {
LOpcode op = LOpcode(u.code & ~LIR64);
LOpcode op = LOpcode(firstWord.code & ~LIR64);
return op == LIR_sti;
}
bool isLoad() const {
LOpcode op = u.code;
LOpcode op = firstWord.code;
return op == LIR_ldq || op == LIR_ld || op == LIR_ldc ||
op == LIR_ldqc || op == LIR_ldcs;
}
bool isGuard() const {
LOpcode op = u.code;
LOpcode op = firstWord.code;
return op == LIR_x || op == LIR_xf || op == LIR_xt ||
op == LIR_loop || op == LIR_xbarrier || op == LIR_xtbl;
}
// True if the instruction is a 32-bit or smaller constant integer.
bool isconst() const { return u.code == LIR_int; }
bool isconst() const { return firstWord.code == LIR_int; }
// True if the instruction is a 32-bit or smaller constant integer and
// has the value val when treated as a 32-bit signed integer.
bool isconstval(int32_t val) const;
@ -337,14 +320,11 @@ namespace nanojit
return isop(LIR_jt) || isop(LIR_jf) || isop(LIR_j);
}
void setimm32(int32_t x) { i.imm32 = x; }
// Set the resv member. Should only be used on instructions that use
// that. If you're not sure, you shouldn't be calling it.
void setresv(uint32_t resv) {
NanoAssert(isU8(resv));
u.resv = resv;
}
// Set the opcode and clear resv.
void initOpcodeAndClearResv(LOpcode);
Reservation* initResv();
void clearResv();
// operand-setting methods
void setOprnd1(LIns* r) { u.oprnd_1 = r; }
void setOprnd2(LIns* r) { u.oprnd_2 = r; }

View File

@ -604,7 +604,7 @@ Assembler::asm_restore(LInsp i, Reservation *resv, Register r)
// asm_ld_imm will automatically select between LDR and MOV as
// appropriate.
if (!resv->arIndex)
reserveFree(i);
i->clearResv();
asm_ld_imm(r, i->imm32());
#endif
} else {

View File

@ -303,7 +303,7 @@ namespace nanojit
}
else if (i->isconst()) {
if (!resv->arIndex) {
reserveFree(i);
i->clearResv();
}
int v = i->imm32();
SET32(v, r);

View File

@ -445,7 +445,7 @@ namespace nanojit
}
else if (i->isconst()) {
if (!resv->arIndex) {
reserveFree(i);
i->clearResv();
}
LDi(r, i->imm32());
}