Bug 512181 - nanojit: rework TMFLAGS=assembly,regalloc,activation. r=edwsmith.

--HG--
extra : convert_revision : 43e64a1135f17761aad95ee7ce2d1692aa937579
This commit is contained in:
Nicholas Nethercote 2009-11-24 22:38:51 -08:00
Родитель 67ada8c5e1
Коммит a4ebd385c0
12 изменённых файлов: 129 добавлений и 143 удалений

Просмотреть файл

@ -81,6 +81,7 @@ namespace nanojit
(void)logc;
verbose_only( _logc = logc; )
verbose_only( _outputCache = 0; )
verbose_only( outline[0] = '\0'; )
verbose_only( outlineEOL[0] = '\0'; )
verbose_only( outputAddr = false; )
@ -142,6 +143,9 @@ namespace nanojit
vicIns->setReg(UnknownReg);
// Restore vicIns.
verbose_only( if (_logc->lcbits & LC_Assembly) {
setOutputForEOL(" <= restore %s",
_thisfrag->lirbuf->names->formatRef(vicIns)); } )
asm_restore(vicIns, vicIns->resv(), r);
// r ends up staying active, but the LIns defining it changes.
@ -495,8 +499,8 @@ namespace nanojit
{
int d = disp(ins);
Register r = ins->getReg();
verbose_only( if (d && (_logc->lcbits & LC_RegAlloc)) {
outputForEOL(" <= spill %s",
verbose_only( if (d && (_logc->lcbits & LC_Assembly)) {
setOutputForEOL(" <= spill %s",
_thisfrag->lirbuf->names->formatRef(ins)); } )
asm_spill(r, d, pop, ins->isQuad());
}
@ -554,6 +558,9 @@ namespace nanojit
vic->setReg(UnknownReg);
// Restore vic.
verbose_only( if (_logc->lcbits & LC_Assembly) {
setOutputForEOL(" <= restore %s",
_thisfrag->lirbuf->names->formatRef(vic)); } )
asm_restore(vic, vic->resv(), r);
}
@ -949,6 +956,17 @@ namespace nanojit
if (!required)
continue;
#ifdef NJ_VERBOSE
// Output the register post-state and/or activation post-state.
// Because asm output comes in reverse order, doing it now means
// it is printed after the LIR and asm, exactly when the
// post-state should be shown.
if ((_logc->lcbits & LC_Assembly) && (_logc->lcbits & LC_Activation))
printActivationState();
if ((_logc->lcbits & LC_Assembly) && (_logc->lcbits & LC_RegAlloc))
printRegState();
#endif
LOpcode op = ins->opcode();
switch(op)
{
@ -1557,8 +1575,6 @@ namespace nanojit
void Assembler::arFree(uint32_t idx)
{
verbose_only( printActivationState(" >FP"); )
AR &ar = _activation;
LIns *i = ar.entry[idx];
NanoAssert(i != 0);
@ -1569,19 +1585,46 @@ namespace nanojit
}
#ifdef NJ_VERBOSE
void Assembler::printActivationState(const char* what)
void Assembler::printRegState()
{
if (!(_logc->lcbits & LC_Activation))
return;
char* s = &outline[0];
VMPI_memset(s, ' ', 45); s[45] = '\0';
VMPI_memset(s, ' ', 26); s[26] = '\0';
s += VMPI_strlen(s);
VMPI_sprintf(s, "%s", what);
VMPI_sprintf(s, "RR");
s += VMPI_strlen(s);
for (Register r = FirstReg; r <= LastReg; r = nextreg(r)) {
LIns *ins = _allocator.getActive(r);
if (ins) {
NanoAssertMsg(!_allocator.isFree(r),
"Coding error; register is both free and active! " );
const char* n = _thisfrag->lirbuf->names->formatRef(ins);
if (ins->isop(LIR_param) && ins->paramKind()==1 &&
r == Assembler::savedRegs[ins->paramArg()])
{
// dont print callee-saved regs that arent used
continue;
}
const char* rname = ins->isQuad() ? fpn(r) : gpn(r);
VMPI_sprintf(s, " %s(%s)", rname, n);
s += VMPI_strlen(s);
}
}
output();
}
void Assembler::printActivationState()
{
char* s = &outline[0];
VMPI_memset(s, ' ', 26); s[26] = '\0';
s += VMPI_strlen(s);
VMPI_sprintf(s, "AR");
s += VMPI_strlen(s);
int32_t max = _activation.tos < NJ_MAX_STACK_ENTRY ? _activation.tos : NJ_MAX_STACK_ENTRY;
for(int32_t i = _activation.lowwatermark; i < max; i++) {
for (int32_t i = _activation.lowwatermark; i < max; i++) {
LIns *ins = _activation.entry[i];
if (ins) {
const char* n = _thisfrag->lirbuf->names->formatRef(ins);
@ -1605,7 +1648,7 @@ namespace nanojit
}
s += VMPI_strlen(s);
}
output(&outline[0]);
output();
}
#endif
@ -1625,7 +1668,6 @@ namespace nanojit
int32_t start = ar.lowwatermark;
int32_t i = 0;
NanoAssert(start>0);
verbose_only( printActivationState(" <FP"); )
if (size == 1) {
// easy most common case -- find a hole, or make the frame bigger
@ -1903,74 +1945,43 @@ namespace nanojit
}
#ifdef NJ_VERBOSE
// "outline" must be able to hold the output line in addition to the
// outlineEOL buffer, which is concatenated onto outline just before it
// is printed.
char Assembler::outline[8192];
char Assembler::outlineEOL[512];
void Assembler::outputForEOL(const char* format, ...)
void Assembler::output()
{
va_list args;
va_start(args, format);
// The +1 is for the terminating NUL char.
VMPI_strncat(outline, outlineEOL, sizeof(outline)-(strlen(outline)+1));
if (_outputCache) {
char* str = new (alloc) char[VMPI_strlen(outline)+1];
VMPI_strcpy(str, outline);
_outputCache->insert(str);
} else {
_logc->printf("%s\n", outline);
}
outline[0] = '\0';
outlineEOL[0] = '\0';
vsprintf(outlineEOL, format, args);
}
void Assembler::outputf(const char* format, ...)
{
va_list args;
va_start(args, format);
outline[0] = '\0';
vsprintf(outline, format, args);
output();
}
// Format the output string and remember the number of characters
// that were written.
uint32_t outline_len = vsprintf(outline, format, args);
void Assembler::setOutputForEOL(const char* format, ...)
{
va_list args;
va_start(args, format);
// Add the EOL string to the output, ensuring that we leave enough
// space for the terminating NULL character, then reset it so it
// doesn't repeat on the next outputf.
VMPI_strncat(outline, outlineEOL, sizeof(outline)-(outline_len+1));
outlineEOL[0] = '\0';
output(outline);
}
void Assembler::output(const char* s)
{
if (_outputCache)
{
char* str = new (alloc) char[VMPI_strlen(s)+1];
VMPI_strcpy(str, s);
_outputCache->insert(str);
}
else
{
_logc->printf("%s\n", s);
}
}
void Assembler::output_asm(const char* s)
{
if (!(_logc->lcbits & LC_Assembly))
return;
// Add the EOL string to the output, ensuring that we leave enough
// space for the terminating NULL character, then reset it so it
// doesn't repeat on the next outputf.
VMPI_strncat(outline, outlineEOL, sizeof(outline)-(strlen(outline)+1));
outlineEOL[0] = '\0';
output(s);
}
char* Assembler::outputAlign(char *s, int col)
{
int len = (int)VMPI_strlen(s);
int add = ((col-len)>0) ? col-len : 1;
VMPI_memset(&s[len], ' ', add);
s[col] = '\0';
return &s[col];
vsprintf(outlineEOL, format, args);
}
#endif // NJ_VERBOSE

Просмотреть файл

@ -189,25 +189,41 @@ namespace nanojit
friend class VerboseBlockReader;
public:
#ifdef NJ_VERBOSE
static char outline[8192];
static char outlineEOL[512]; // string to be added to the end of the line
static char* outputAlign(char* s, int col);
void outputForEOL(const char* format, ...);
void output(const char* s);
void outputf(const char* format, ...);
void output_asm(const char* s);
bool outputAddr, vpad[3]; // if outputAddr=true then next asm instr. will include address in output
void printActivationState(const char* what);
// Log controller object. Contains what-stuff-should-we-print
// bits, and a sink function for debug printing.
LogControl* _logc;
// Buffer for holding text as we generate it in reverse order.
StringList* _outputCache;
// Log controller object. Contains what-stuff-should-we-print
// bits, and a sink function for debug printing
LogControl* _logc;
// Outputs the format string and 'outlineEOL', and resets
// 'outline' and 'outlineEOL'.
void outputf(const char* format, ...);
private:
// Buffer used in most of the output function. It must big enough
// to hold both the output line and the 'outlineEOL' buffer, which
// is concatenated onto 'outline' just before it is printed.
static char outline[8192];
// Buffer used to hold extra text to be printed at the end of some
// lines.
static char outlineEOL[512];
// If outputAddr=true the next asm instruction output will
// be prepended with its address.
bool outputAddr, vpad[3];
// Outputs 'outline' and 'outlineEOL', and resets them both.
// Output goes to '_outputCache' if it's non-NULL, or is printed
// directly via '_logc'.
void output();
// Sets 'outlineEOL'.
void setOutputForEOL(const char* format, ...);
void printRegState();
void printActivationState();
#endif // NJ_VERBOSE
public:
#ifdef VTUNE
avmplus::CodegenLIR *cgen;
#endif
@ -388,10 +404,10 @@ namespace nanojit
// since we generate backwards the depth is negative
inline void fpu_push() {
debug_only( ++_fpuStkDepth; /*char foo[8]= "FPUSTK0"; foo[6]-=_fpuStkDepth; output_asm(foo);*/ NanoAssert(_fpuStkDepth<=0); )
debug_only( ++_fpuStkDepth; NanoAssert(_fpuStkDepth<=0); )
}
inline void fpu_pop() {
debug_only( --_fpuStkDepth; /*char foo[8]= "FPUSTK0"; foo[6]-=_fpuStkDepth; output_asm(foo);*/ NanoAssert(_fpuStkDepth<=0); )
debug_only( --_fpuStkDepth; NanoAssert(_fpuStkDepth<=0); )
}
#endif
avmplus::Config &config;

Просмотреть файл

@ -1868,7 +1868,7 @@ namespace nanojit
case LIR_qjoin:
VMPI_sprintf(s, "%s (%s), %s", lirNames[op],
formatIns(i->oprnd1()),
formatRef(i->oprnd1()),
formatRef(i->oprnd2()));
break;

Просмотреть файл

@ -181,6 +181,10 @@ namespace nanojit {
#define gpn(r) regNames[(r)]
#define fpn(r) regNames[(r)]
#elif defined(NJ_VERBOSE)
// Used for printing native instructions. Like Assembler::outputf(),
// but only outputs if LC_Assembly is set. Also prepends the output
// with the address of the current native instruction if
// LC_NoCodeAddrs is not set.
#define asm_output(...) do { \
counter_increment(native); \
if (_logc->lcbits & LC_Assembly) { \
@ -190,9 +194,7 @@ namespace nanojit {
else \
VMPI_memset(outline, (int)' ', 10+3); \
sprintf(&outline[13], ##__VA_ARGS__); \
Assembler::outputAlign(outline, 35); \
_allocator.formatRegisters(outline, _thisfrag); \
Assembler::output_asm(outline); \
output(); \
outputAddr=(_logc->lcbits & LC_NoCodeAddrs) ? false : true; \
} \
} while (0) /* no semi */

Просмотреть файл

@ -1230,9 +1230,6 @@ Assembler::asm_restore(LInsp i, Reservation *, Register r)
}
}
}
verbose_only(
asm_output(" restore %s",_thisfrag->lirbuf->names->formatRef(i));
)
}
void
@ -1283,7 +1280,7 @@ Assembler::asm_load64(LInsp ins)
NanoAssert(IsGpReg(rb));
freeRsrcOf(ins, false);
//output("--- load64: Finished register allocation.");
//outputf("--- load64: Finished register allocation.");
if (ARM_VFP && isKnownReg(rr)) {
// VFP is enabled and the result will go into a register.

Просмотреть файл

@ -592,9 +592,6 @@ namespace nanojit
} else {
LWZ(r, d, FP);
}
verbose_only( if (_logc->lcbits & LC_RegAlloc) {
outputForEOL(" <= restore %s",
_thisfrag->lirbuf->names->formatRef(i)); } )
}
}

Просмотреть файл

@ -98,7 +98,7 @@ namespace nanojit
verbose_only(
if (_logc->lcbits & LC_Assembly) {
outputf(" %p:",_nIns);
output(" patch entry:");
outputf(" patch entry:");
})
NIns *patchEntry = _nIns;
@ -282,9 +282,6 @@ namespace nanojit
ADD(FP, L2, r);
int32_t d = disp(i);
SET32(d, L2);
verbose_only(if (_logc->lcbits & LC_RegAlloc) {
outputf(" remat %s size %d", _thisfrag->lirbuf->names->formatRef(i), i->size());
})
}
else if (i->isconst()) {
if (!i->getArIndex()) {
@ -299,9 +296,6 @@ namespace nanojit
} else {
LDSW32(FP, d, r);
}
verbose_only(if (_logc->lcbits & LC_RegAlloc) {
outputf(" restore %s", _thisfrag->lirbuf->names->formatRef(i));
})
}
}

Просмотреть файл

@ -495,6 +495,10 @@ namespace nanojit
void Assembler::JMP32(S n, NIns* t) { emit_target32(n,X64_jmp, t); asm_output("jmp %p", t); }
void Assembler::JMPX(R indexreg, NIns** table) { emitrxb_imm(X64_jmpx, (R)0, indexreg, (Register)5, (int32_t)(uintptr_t)table); asm_output("jmpq [%s*8 + %p]", RQ(indexreg), (void*)table); }
void Assembler::JMPXB(R indexreg, R tablereg) { emitxb(X64_jmpxb, indexreg, tablereg); asm_output("jmp [%s*8 + %s]", RQ(indexreg), RQ(tablereg)); }
void Assembler::JO( S n, NIns* t) { emit_target32(n,X64_jo, t); asm_output("jo %p", t); }
void Assembler::JE( S n, NIns* t) { emit_target32(n,X64_je, t); asm_output("je %p", t); }
void Assembler::JL( S n, NIns* t) { emit_target32(n,X64_jl, t); asm_output("jl %p", t); }
@ -1239,7 +1243,6 @@ namespace nanojit
}
void Assembler::asm_restore(LIns *ins, Reservation *, Register r) {
(void) r;
if (ins->isop(LIR_alloc)) {
int d = disp(ins);
LEAQRM(r, d, FP);
@ -1270,9 +1273,6 @@ namespace nanojit
MOVLRM(r, d, FP);
}
}
verbose_only( if (_logc->lcbits & LC_RegAlloc) {
outputForEOL(" <= restore %s",
_thisfrag->lirbuf->names->formatRef(ins)); } )
}
void Assembler::asm_cond(LIns *ins) {
@ -1746,18 +1746,18 @@ namespace nanojit
void Assembler::asm_jtbl(LIns* ins, NIns** table)
{
// exclude R12 becuase ESP and R12 cannot be used as an index
// exclude R12 because ESP and R12 cannot be used as an index
// (index=100 in SIB means "none")
Register indexreg = findRegFor(ins->oprnd1(), GpRegs & ~rmask(R12));
if (isS32((intptr_t)table)) {
// table is in low 2GB or high 2GB, can use absolute addressing
// jmpq [indexreg*8 + table]
emitrxb_imm(X64_jmpx, (Register)0, indexreg, (Register)5, (int32_t)(uintptr_t)table);
JMPX(indexreg, table);
} else {
// don't use R13 for base because we want to use mod=00, i.e. [index*8+base + 0]
Register tablereg = registerAllocTmp(GpRegs & ~(rmask(indexreg)|rmask(R13)));
// jmp [indexreg*8 + tablereg]
emitxb(X64_jmpxb, indexreg, tablereg);
JMPXB(indexreg, tablereg);
// tablereg <- #table
asm_quad(tablereg, (uint64_t)table);
}

Просмотреть файл

@ -502,6 +502,8 @@ namespace nanojit
void MOVSDMR(Register r1, int d, Register r2);\
void JMP8(size_t n, NIns* t);\
void JMP32(size_t n, NIns* t);\
void JMPX(Register indexreg, NIns** table);\
void JMPXB(Register indexreg, Register tablereg);\
void JO(size_t n, NIns* t);\
void JE(size_t n, NIns* t);\
void JL(size_t n, NIns* t);\

Просмотреть файл

@ -401,9 +401,6 @@ namespace nanojit
uint32_t arg;
uint32_t abi_regcount;
if (i->isop(LIR_alloc)) {
verbose_only( if (_logc->lcbits & LC_RegAlloc) {
outputForEOL(" <= remat %s size %d",
_thisfrag->lirbuf->names->formatRef(i), i->size()); } )
LEA(r, disp(i), FP);
}
else if (i->isconst()) {
@ -429,9 +426,6 @@ namespace nanojit
}
else {
int d = findMemFor(i);
verbose_only( if (_logc->lcbits & LC_RegAlloc) {
outputForEOL(" <= restore %s",
_thisfrag->lirbuf->names->formatRef(i)); } )
asm_load(d,r);
}
}

Просмотреть файл

@ -43,31 +43,6 @@ namespace nanojit
{
#ifdef FEATURE_NANOJIT
#ifdef NJ_VERBOSE
void RegAlloc::formatRegisters(char* s, Fragment *frag)
{
if (!frag || !frag->lirbuf)
return;
LirNameMap *names = frag->lirbuf->names;
for (Register r = FirstReg; r <= LastReg; r = nextreg(r))
{
LIns *ins = getActive(r);
if (!ins)
continue;
NanoAssertMsg(!isFree(r), "Coding error; register is both free and active! " );
if (ins->isop(LIR_param) && ins->paramKind()==1 && r == Assembler::savedRegs[ins->paramArg()]) {
// dont print callee-saved regs that arent used
continue;
}
s += VMPI_strlen(s);
const char* rname = ins->isQuad() ? fpn(r) : gpn(r);
VMPI_sprintf(s, " %s(%s)", rname, names->formatRef(ins));
}
}
#endif /* NJ_VERBOSE */
#ifdef _DEBUG
uint32_t RegAlloc::countActive()

Просмотреть файл

@ -179,8 +179,6 @@ namespace nanojit
RegisterMask free;
int32_t priority;
verbose_only( void formatRegisters(char* s, Fragment*); )
DECLARE_PLATFORM_REGALLOC()
};
}