mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 490947 - nanojit: remove reservation table. r=gal,edwsmith
This commit is contained in:
parent
6c4c7621f3
commit
90746fda0d
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 ---------------------------------- ]
|
||||
|
@ -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; }
|
||||
|
@ -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 {
|
||||
|
@ -303,7 +303,7 @@ namespace nanojit
|
||||
}
|
||||
else if (i->isconst()) {
|
||||
if (!resv->arIndex) {
|
||||
reserveFree(i);
|
||||
i->clearResv();
|
||||
}
|
||||
int v = i->imm32();
|
||||
SET32(v, r);
|
||||
|
@ -445,7 +445,7 @@ namespace nanojit
|
||||
}
|
||||
else if (i->isconst()) {
|
||||
if (!resv->arIndex) {
|
||||
reserveFree(i);
|
||||
i->clearResv();
|
||||
}
|
||||
LDi(r, i->imm32());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user