diff --git a/js/src/nanojit/Assembler.cpp b/js/src/nanojit/Assembler.cpp index 731e3415078..3005d0e55ce 100644 --- a/js/src/nanojit/Assembler.cpp +++ b/js/src/nanojit/Assembler.cpp @@ -1357,11 +1357,21 @@ namespace nanojit // if (_logc->lcbits & LC_Assembly) { outputf(" %s", _thisfrag->lirbuf->names->formatIns(ins)); - // Special case: a guard condition won't get printed next time - // around the loop, so do it now. if (ins->isGuard() && ins->oprnd1()) { - outputf(" %s # handled by the guard", - _thisfrag->lirbuf->names->formatIns(ins->oprnd1())); + // Special case: code is generated for guard conditions at + // the same time that code is generated for the guard + // itself. If the condition is only used by the guard, we + // must print it now otherwise it won't get printed. So + // we do print it now, with an explanatory comment. If + // the condition *is* used again we'll end up printing it + // twice, but that's ok. + outputf(" %s # codegen'd with the %s", + _thisfrag->lirbuf->names->formatIns(ins->oprnd1()), lirNames[op]); + + } else if (ins->isop(LIR_cmov) || ins->isop(LIR_qcmov)) { + // Likewise for cmov conditions. + outputf(" %s # codegen'd with the %s", + _thisfrag->lirbuf->names->formatIns(ins->oprnd1()), lirNames[op]); } } #endif diff --git a/js/src/nanojit/Nativei386.cpp b/js/src/nanojit/Nativei386.cpp index bfc3fab674c..f6462bba61b 100644 --- a/js/src/nanojit/Nativei386.cpp +++ b/js/src/nanojit/Nativei386.cpp @@ -686,6 +686,36 @@ namespace nanojit JMP(exit); } + // This generates a 'test' or 'cmp' instruction for a condition, which + // causes the condition codes to be set appropriately. It's used with + // conditional branches, conditional moves, and when generating + // conditional values. For example: + // + // LIR: eq1 = eq a, 0 + // LIR: xf1: xf eq1 -> ... + // asm: test edx, edx # generated by this function + // asm: je ... + // + // If this is the only use of eq1, then on entry 'cond' is *not* marked as + // used, and we do not allocate a register for it. That's because its + // result ends up in the condition codes rather than a normal register. + // This doesn't get recorded in the regstate and so the asm code that + // consumes the result (eg. a conditional branch like 'je') must follow + // shortly after. + // + // If eq1 is instead used again later, we will also generate code + // (eg. in asm_cond()) to compute it into a normal register, something + // like this: + // + // LIR: eq1 = eq a, 0 + // LIR: test edx, edx + // asm: sete ebx + // asm: movzx ebx, ebx + // + // In this case we end up computing the condition twice, but that's ok, as + // it's just as short as testing eq1's value in the code generated for the + // guard. + // void Assembler::asm_cmp(LIns *cond) { LOpcode condop = cond->opcode();