diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 59b0fe93147b..18b64b96a593 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -309,7 +309,6 @@ js_InitJITLogController ( void ) if (strstr(tmf, "readlir")) bits |= LC_ReadLIR; if (strstr(tmf, "aftersf_sp")) bits |= LC_AfterSF_SP; if (strstr(tmf, "aftersf_rp")) bits |= LC_AfterSF_RP; - if (strstr(tmf, "afterdeadf")) bits |= LC_AfterDeadF; if (strstr(tmf, "regalloc")) bits |= LC_RegAlloc; if (strstr(tmf, "assembly")) bits |= LC_Assembly; if (strstr(tmf, "nocodeaddrs")) bits |= LC_NoCodeAddrs; @@ -317,7 +316,7 @@ js_InitJITLogController ( void ) if (strstr(tmf, "full")) { bits |= LC_TMMinimal | LC_TMTracer | LC_TMRecorder | LC_TMPatcher | LC_TMAbort | LC_TMAbort | LC_TMStats | LC_TMRegexp | LC_Liveness | LC_ReadLIR | - LC_AfterSF_SP | LC_AfterSF_RP | LC_AfterDeadF | LC_RegAlloc | LC_Assembly; + LC_AfterSF_SP | LC_AfterSF_RP | LC_RegAlloc | LC_Assembly; } js_LogController.lcbits = bits; @@ -347,7 +346,6 @@ js_InitJITLogController ( void ) printf(" readlir show LIR as it enters the reader pipeline\n"); printf(" aftersf_sp show LIR after StackFilter(sp)\n"); printf(" aftersf_rp show LIR after StackFilter(rp)\n"); - printf(" afterdeadf show LIR after DeadCodeFilter\n"); printf(" regalloc show regalloc details\n"); printf(" assembly show final aggregated assembly code\n"); printf(" nocodeaddrs don't show code addresses in assembly listings\n"); diff --git a/js/src/nanojit/Assembler.cpp b/js/src/nanojit/Assembler.cpp index 0d3eda572a4c..150f6389670d 100644 --- a/js/src/nanojit/Assembler.cpp +++ b/js/src/nanojit/Assembler.cpp @@ -58,35 +58,6 @@ namespace nanojit { int UseSoftfloat = 0; - class DeadCodeFilter: public LirFilter - { - bool ignoreInstruction(LInsp ins) - { - LOpcode op = ins->opcode(); - if (ins->isStore() || - op == LIR_loop || - op == LIR_label || - op == LIR_live || - op == LIR_start || - ins->isRet()) { - return false; - } - return !ins->resv()->used; - } - - public: - DeadCodeFilter(LirFilter *in) : LirFilter(in) {} - LInsp read() { - for (;;) { - LInsp i = in->read(); - if (i->isGuard() || i->isBranch() - || (i->isCall() && !i->isCse()) - || !ignoreInstruction(i)) - return i; - } - } - }; - #ifdef NJ_VERBOSE class VerboseBlockReader: public LirFilter { @@ -821,8 +792,7 @@ namespace nanojit verbose_only( ReverseLister *pp_init = NULL, *pp_after_sf1 = NULL, - *pp_after_sf2 = NULL, - *pp_after_dead = NULL; + *pp_after_sf2 = NULL; ) // set up backwards pipeline: assembler -> StackFilter -> LirReader @@ -858,20 +828,10 @@ namespace nanojit verbose_only( if (_logc->lcbits & LC_AfterSF_RP) { pp_after_sf2 = new ReverseLister(prev, gc, frag->lirbuf->names, _logc, - "After StoreFilter(rp)"); + "After StoreFilter(rp) (final LIR)"); prev = pp_after_sf2; }) - // DEAD CODE FILTER - DeadCodeFilter deadfilter(prev); - prev = &deadfilter; - - verbose_only( if (_logc->lcbits & LC_AfterDeadF) { - pp_after_dead = new ReverseLister(prev, gc, frag->lirbuf->names, _logc, - "After DeadFilter == Final LIR"); - prev = pp_after_dead; - }) - // end of pipeline verbose_only( VerboseBlockReader vbr(prev, this, frag->lirbuf->names); @@ -920,8 +880,7 @@ namespace nanojit if (pp_init) delete pp_init; if (pp_after_sf1) delete pp_after_sf1; if (pp_after_sf2) delete pp_after_sf2; - if (pp_after_dead) delete pp_after_dead; - ) + ) } void Assembler::endAssembly(Fragment* frag, NInsList& loopJumps) @@ -1128,8 +1087,49 @@ namespace nanojit InsList pending_lives(_gc); - for (LInsp ins = reader->read(); !ins->isop(LIR_start) && !error(); ins = reader->read()) + for (LInsp ins = reader->read(); !ins->isop(LIR_start) && !error(); + ins = reader->read()) { + /* What's going on here: we're visiting all the LIR nodes + in the buffer, working strictly backwards in + buffer-order, and generating machine instructions for + them as we go. + + But we're not visiting all of them, only the ones that + made it through the filter pipeline that we're reading + from. For each visited node, we first determine + whether it's actually necessary, and if not skip it. + Otherwise we fall into the big switch, which calls a + target-specific routine to generate the required + instructions. + + For each node, we need to decide whether we need to + generate any code. This is a rather subtle part of the + generation algorithm. + + There are two categories: + + "statement" nodes -- ones with side effects. Anything + that could change control flow or the state of memory. + These we must absolutely retain. That accounts for the + first part of the following disjunction for 'required'. + + The rest are "value" nodes, which compute a value based + only on the operands to the node (and, in the case of + loads, the state of memory). It's safe to omit these + if the value(s) computed are not used later. Since + we're visiting nodes in reverse order, if some + previously visited (viz, later in the buffer ordering) + node uses the value computed by this node, then this + node will already have a register assigned to hold that + value. Hence we can consult the reservation to detect + whether the value is in fact used. That's the second + part of the disjunction. + */ + bool required = ins->isStmt() || ins->resv()->used; + if (!required) + continue; + LOpcode op = ins->opcode(); switch(op) { diff --git a/js/src/nanojit/LIR.h b/js/src/nanojit/LIR.h index d11a272d8c87..9449b111848c 100644 --- a/js/src/nanojit/LIR.h +++ b/js/src/nanojit/LIR.h @@ -681,6 +681,20 @@ namespace nanojit return isop(LIR_jt) || isop(LIR_jf) || isop(LIR_j); } + // Return true if removal of 'ins' from a LIR fragment could + // possibly change the behaviour of that fragment, even if any + // value computed by 'ins' is not used later in the fragment. + // In other words, can 'ins' possible alter control flow or memory? + // Note, this assumes that loads will never fault and hence cannot + // affect the control flow. + bool isStmt() { + return isGuard() || isBranch() || + (isCall() && !isCse()) || + isStore() || + isop(LIR_loop) || isop(LIR_label) || isop(LIR_live) || + isRet(); + } + void setTarget(LIns* t); LIns* getTarget(); diff --git a/js/src/nanojit/nanojit.h b/js/src/nanojit/nanojit.h index 743f5e72db62..68e8a20c36a3 100644 --- a/js/src/nanojit/nanojit.h +++ b/js/src/nanojit/nanojit.h @@ -268,11 +268,10 @@ namespace nanojit { and below, so that callers can use bits 16 and above for themselves. */ // TODO: add entries for the writer pipeline - LC_Liveness = 1<<7, // (show LIR liveness analysis) - LC_ReadLIR = 1<<6, // As read from LirBuffer - LC_AfterSF_SP = 1<<5, // After StackFilter(sp) - LC_AfterSF_RP = 1<<4, // After StackFilter(rp) - LC_AfterDeadF = 1<<3, // After DeadFilter + LC_Liveness = 1<<6, // (show LIR liveness analysis) + LC_ReadLIR = 1<<5, // As read from LirBuffer + LC_AfterSF_SP = 1<<4, // After StackFilter(sp) + LC_AfterSF_RP = 1<<3, // After StackFilter(rp) LC_RegAlloc = 1<<2, // stuff to do with reg alloc LC_Assembly = 1<<1, // final assembly LC_NoCodeAddrs = 1<<0 // (don't show code addresses on asm output)