Bug 540368 - nanojit: split LIR_qlo, LIR_live and LIR_ret into two opcodes each to faciliate LIR type-checking (NJ-specific part). r=edwsmith.

--HG--
extra : convert_revision : 54cf6d39a21dc1e209d3e0e48bb6c2b61ab5f909
This commit is contained in:
Nicholas Nethercote 2010-01-28 08:45:29 +11:00
Родитель feb28e66a5
Коммит e563ce0389
12 изменённых файлов: 156 добавлений и 113 удалений

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

@ -96,8 +96,8 @@ CLASS( LOP_B_FF, 0, 3) // 63% LIR_feq, LIR_flt, etc
CLASS( LOP_Q_I, 1, 2) // 65% LIR_i2q, LIR_u2q
CLASS( LOP_F_I, 0, 2) // 67% LIR_i2f, LIR_u2f
CLASS( LOP_I_F, 0, 2) // 69% LIR_qlo, LIR_qhi, LIR_f2i
CLASS( LOP_I_Q, 1, 1) // 68% LIR_q2i
CLASS( LOP_I_F, 0, 1) // 69% LIR_qlo, LIR_qhi, LIR_f2i
CLASS( LOP_F_II, 0, 1) // 70% LIR_qjoin
CLASS( LLD_I, 0, 3) // 73% LIR_ld, LIR_ldc, LIR_ld*b, LIR_ld*s

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

@ -892,12 +892,14 @@ FragmentAssembler::assembleFragment(LirTokenStream &in, bool implicitBegin, cons
break;
case LIR_live:
case LIR_qlive:
case LIR_flive:
case LIR_neg:
case LIR_fneg:
case LIR_not:
case LIR_qlo:
case LIR_qhi:
case LIR_q2i:
case LIR_ov:
case LIR_i2q:
case LIR_u2q:
@ -1086,6 +1088,7 @@ FragmentAssembler::assembleFragment(LirTokenStream &in, bool implicitBegin, cons
case LIR_line:
case LIR_xtbl:
case LIR_jtbl:
case LIR_qret:
nyi(op);
break;
@ -1260,19 +1263,20 @@ const CallInfo ci_N_IQF = CI(f_N_IQF, argMask(I32, 1, 3) |
// sufficiently big that it's spread across multiple chunks.
//
// The following instructions aren't generated yet:
// - iparam/qparam (hard to test beyond what is auto-generated in fragment
// - LIR_iparam/LIR_qparam (hard to test beyond what is auto-generated in fragment
// prologues)
// - live/flive
// - callh
// - x/xt/xf/xtbl (hard to test without having multiple fragments; when we
// only have one fragment we don't really want to leave it early)
// - ret/fret (hard to test without having multiple fragments)
// - j/jt/jf/ji/label (ji is not implemented in NJ)
// - ov (takes an arithmetic (int or FP) value as operand, and must
// - LIR_live/LIR_qlive/LIR_flive
// - LIR_callh
// - LIR_x/LIR_xt/LIR_xf/LIR_xtbl (hard to test without having multiple
// fragments; when we only have one fragment we don't really want to leave
// it early)
// - LIR_ret/LIR_qret/LIR_fret (hard to test without having multiple fragments)
// - LIR_j/LIR_jt/LIR_jf/LIR_jtbl/LIR_label
// - LIR_ov (takes an arithmetic (int or FP) value as operand, and must
// immediately follow it to be safe... not that that really matters in
// randomly generated code)
// - file/line (#ifdef VTUNE only)
// - fmod (not implemented in NJ)
// - LIR_file/LIR_line (#ifdef VTUNE only)
// - LIR_fmod (not implemented in NJ backends)
//
void
FragmentAssembler::assembleRandomFragment(int nIns)
@ -1368,6 +1372,9 @@ FragmentAssembler::assembleRandomFragment(int nIns)
Q_I_ops.push_back(LIR_i2q);
Q_I_ops.push_back(LIR_u2q);
vector<LOpcode> I_Q_ops;
I_Q_ops.push_back(LIR_q2i);
vector<LOpcode> F_I_ops;
F_I_ops.push_back(LIR_i2f);
F_I_ops.push_back(LIR_u2f);
@ -1707,6 +1714,14 @@ FragmentAssembler::assembleRandomFragment(int nIns)
}
break;
case LOP_I_Q:
if (!Qs.empty()) {
ins = mLir->ins1(rndPick(I_Q_ops), rndPick(Qs));
addOrReplace(Is, ins);
n++;
}
break;
case LOP_I_F:
// XXX: NativeX64 doesn't implement qhi yet (and it may not need to).
#if !defined NANOJIT_X64

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

@ -1199,13 +1199,15 @@ namespace nanojit
{
NanoAssert(_thisfrag->nStaticExits == 0);
// trace must end with LIR_x, LIR_[f]ret, LIR_xtbl, or LIR_[f]live
NanoAssert(reader->pos()->isop(LIR_x) ||
reader->pos()->isop(LIR_ret) ||
reader->pos()->isop(LIR_fret) ||
reader->pos()->isop(LIR_xtbl) ||
reader->pos()->isop(LIR_flive) ||
reader->pos()->isop(LIR_live));
// The trace must end with one of these opcodes.
NanoAssert(reader->pos()->isop(LIR_x) ||
reader->pos()->isop(LIR_xtbl) ||
reader->pos()->isop(LIR_ret) ||
reader->pos()->isop(LIR_qret) ||
reader->pos()->isop(LIR_fret) ||
reader->pos()->isop(LIR_live) ||
reader->pos()->isop(LIR_qlive) ||
reader->pos()->isop(LIR_flive));
InsList pending_lives(alloc);
@ -1286,8 +1288,9 @@ namespace nanojit
evictAllActiveRegs();
break;
case LIR_flive:
case LIR_live: {
case LIR_live:
case LIR_qlive:
case LIR_flive: {
countlir_live();
LInsp op1 = ins->oprnd1();
// alloca's are meant to live until the point of the LIR_live instruction, marking
@ -1305,8 +1308,9 @@ namespace nanojit
break;
}
case LIR_fret:
case LIR_ret: {
case LIR_ret:
case LIR_qret:
case LIR_fret: {
countlir_ret();
asm_ret(ins);
break;
@ -1355,6 +1359,12 @@ namespace nanojit
asm_param(ins);
break;
}
case LIR_q2i:
{
countlir_alu();
asm_q2i(ins);
break;
}
case LIR_qlo:
{
countlir_qlo();
@ -1866,9 +1876,9 @@ namespace nanojit
// ensure that exprs spanning the loop are marked live at the end of the loop
reserveSavedRegs();
for (Seq<LIns*> *p = pending_lives.get(); p != NULL; p = p->tail) {
LIns *i = p->head;
NanoAssert(i->isop(LIR_live) || i->isop(LIR_flive));
LIns *op1 = i->oprnd1();
LIns *ins = p->head;
NanoAssert(ins->isop(LIR_live) || ins->isop(LIR_qlive) || ins->isop(LIR_flive));
LIns *op1 = ins->oprnd1();
// must findMemFor even if we're going to findRegFor; loop-carried
// operands may spill on another edge, and we need them to always
// spill to the same place.
@ -1881,7 +1891,7 @@ namespace nanojit
findMemFor(op1);
}
if (! (op1->isconst() || op1->isconstf() || op1->isconstq()))
findRegFor(op1, i->isop(LIR_flive) ? FpRegs : GpRegs);
findRegFor(op1, ins->isop(LIR_flive) ? FpRegs : GpRegs);
}
// clear this list since we have now dealt with those lifetimes. extending

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

@ -435,6 +435,7 @@ namespace nanojit
void asm_i2f(LInsp ins);
void asm_u2f(LInsp ins);
void asm_f2i(LInsp ins);
void asm_q2i(LInsp ins);
void asm_promote(LIns *ins);
void asm_nongp_copy(Register r, Register s);
void asm_call(LInsp);

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

@ -443,57 +443,61 @@ namespace nanojit
return false;
}
LIns* ExprFilter::ins1(LOpcode v, LIns* i)
LIns* ExprFilter::ins1(LOpcode v, LIns* oprnd)
{
switch (v) {
case LIR_q2i:
if (oprnd->isconstq())
return insImm(oprnd->imm64_0());
break;
case LIR_qlo:
if (i->isconstq())
return insImm(i->imm64_0());
if (i->isop(LIR_qjoin))
return i->oprnd1();
if (oprnd->isconstq())
return insImm(oprnd->imm64_0());
if (oprnd->isop(LIR_qjoin))
return oprnd->oprnd1();
break;
case LIR_qhi:
if (i->isconstq())
return insImm(i->imm64_1());
if (i->isop(LIR_qjoin))
return i->oprnd2();
if (oprnd->isconstq())
return insImm(oprnd->imm64_1());
if (oprnd->isop(LIR_qjoin))
return oprnd->oprnd2();
break;
case LIR_not:
if (i->isconst())
return insImm(~i->imm32());
if (oprnd->isconst())
return insImm(~oprnd->imm32());
involution:
if (v == i->opcode())
return i->oprnd1();
if (v == oprnd->opcode())
return oprnd->oprnd1();
break;
case LIR_neg:
if (i->isconst())
return insImm(-i->imm32());
if (i->isop(LIR_sub)) // -(a-b) = b-a
return out->ins2(LIR_sub, i->oprnd2(), i->oprnd1());
if (oprnd->isconst())
return insImm(-oprnd->imm32());
if (oprnd->isop(LIR_sub)) // -(a-b) = b-a
return out->ins2(LIR_sub, oprnd->oprnd2(), oprnd->oprnd1());
goto involution;
case LIR_fneg:
if (i->isconstq())
return insImmf(-i->imm64f());
if (i->isop(LIR_fsub))
return out->ins2(LIR_fsub, i->oprnd2(), i->oprnd1());
if (oprnd->isconstq())
return insImmf(-oprnd->imm64f());
if (oprnd->isop(LIR_fsub))
return out->ins2(LIR_fsub, oprnd->oprnd2(), oprnd->oprnd1());
goto involution;
case LIR_i2f:
if (i->isconst())
return insImmf(i->imm32());
if (oprnd->isconst())
return insImmf(oprnd->imm32());
break;
case LIR_f2i:
if (i->isconstq())
return insImm(int32_t(i->imm64f()));
if (oprnd->isconstq())
return insImm(int32_t(oprnd->imm64f()));
break;
case LIR_u2f:
if (i->isconst())
return insImmf(uint32_t(i->imm32()));
if (oprnd->isconst())
return insImmf(uint32_t(oprnd->imm32()));
break;
default:
;
}
return out->ins1(v, i);
return out->ins1(v, oprnd);
}
// This is an ugly workaround for an apparent compiler
@ -1521,8 +1525,10 @@ namespace nanojit
case LIR_ld32f:
case LIR_ldc32f:
case LIR_ret:
case LIR_qret:
case LIR_fret:
case LIR_live:
case LIR_qlive:
case LIR_flive:
case LIR_xt:
case LIR_xf:
@ -1540,6 +1546,7 @@ namespace nanojit
case LIR_u2q:
case LIR_i2f:
case LIR_u2f:
case LIR_q2i:
case LIR_f2i:
case LIR_mod:
live.add(ins->oprnd1(), ins);
@ -1848,7 +1855,10 @@ namespace nanojit
break;
case LIR_live:
case LIR_flive:
case LIR_qlive:
case LIR_ret:
case LIR_qret:
case LIR_fret:
VMPI_sprintf(s, "%s %s", lirNames[op], formatRef(i->oprnd1()));
break;
@ -1865,6 +1875,7 @@ namespace nanojit
case LIR_mod:
case LIR_i2q:
case LIR_u2q:
case LIR_q2i:
case LIR_f2i:
VMPI_sprintf(s, "%s = %s %s", formatRef(i), lirNames[op], formatRef(i->oprnd1()));
break;
@ -2315,7 +2326,7 @@ namespace nanojit
void ValidateWriter::errorStructureShouldBe(LOpcode op, const char* argDesc, int argN,
LIns* arg, const char* shouldBeDesc)
{
fprintf(stderr,
NanoAssertMsgf(0,
"\n\n"
" LIR structure error (%s):\n"
" in instruction with opcode: %s\n"
@ -2499,16 +2510,9 @@ namespace nanojit
case LIR_not:
case LIR_i2f:
case LIR_u2f:
formals[0] = LTy_I32;
break;
case LIR_live:
case LIR_ret:
// XXX: LIR_ret is used in TM as if it takes a 32-bit integer
// argument, but it is used in TR as if it takes a word-sized
// integer argument. We should split it into LIR_ret and LIR_qret
// for clarity and consistency with all the other cases, and have
// LIR_pret as a synonym. Don't type-check for now.
nArgs = 0;
formals[0] = LTy_I32;
break;
case LIR_i2q:
@ -2530,15 +2534,14 @@ namespace nanojit
formals[0] = LTy_I32;
break;
case LIR_qlo:
// XXX: LIR_qlo currently has two distinct uses. One is in
// combination with LIR_qhi and LIR_qjoin, for splitting/joining
// F64s. The other is for truncating I64s. Because these have
// different operand types we can't check it here. See bug
// 540368.
nArgs = 0;
case LIR_q2i:
case LIR_qret:
case LIR_qlive:
checkIs64BitPlatform(op);
formals[0] = LTy_I64;
break;
case LIR_qlo:
case LIR_qhi:
checkIs32BitPlatform(op);
formals[0] = LTy_F64;
@ -2551,13 +2554,6 @@ namespace nanojit
formals[0] = LTy_F64;
break;
case LIR_live:
// XXX: should be a unary LTy_I32, but LIR_live is currently also
// used for LTy_I64 values because we don't have LIR_qlive. So
// we can't check it for now. See bug 540368.
nArgs = 0;
break;
case LIR_callh:
checkLInsHasOpcode(op, 1, a, LIR_fcall);
formals[0] = LTy_F64;

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

@ -84,7 +84,9 @@ namespace nanojit
LIR_puge = PTR_SIZE(LIR_uge, LIR_quge),
LIR_alloc = PTR_SIZE(LIR_ialloc, LIR_qalloc),
LIR_pcall = PTR_SIZE(LIR_icall, LIR_qcall),
LIR_param = PTR_SIZE(LIR_iparam, LIR_qparam)
LIR_param = PTR_SIZE(LIR_iparam, LIR_qparam),
LIR_plive = PTR_SIZE(LIR_live, LIR_qlive),
LIR_pret = PTR_SIZE(LIR_ret, LIR_qret)
};
struct GuardRecord;
@ -172,7 +174,7 @@ namespace nanojit
(op >= LIR_quad && op <= LIR_quge);
}
inline bool isRetOpcode(LOpcode op) {
return op == LIR_ret || op == LIR_fret;
return op == LIR_ret || op == LIR_qret || op == LIR_fret;
}
LOpcode f64arith_to_i32arith(LOpcode op);
LOpcode i32cmp_to_i64cmp(LOpcode op);

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

@ -79,8 +79,8 @@ OPDEF(ld, 10, Ld, I32) // 32-bit integer load
OPDEF(ialloc, 11, I, I32) // alloc some stack space (value is 32bit address)
OPDEF(sti, 12, Sti, Void) // 32-bit integer store
OPDEF(ret, 13, Op1, Void) // return a 32-bit integer
OPDEF(live, 14, Op1, Void) // extend live range of reference
OPDEF(flive, 15, Op1, Void) // extend live range of a floating point value reference
OPDEF(live, 14, Op1, Void) // extend live range of a 32-bit integer
OPDEF(flive, 15, Op1, Void) // extend live range of a 64-bit float
OPDEF(icall, 16, C, I32) // subroutine call returning a 32-bit value
OPDEF(sts, 17, Sti, Void) // 16-bit integer store
@ -190,7 +190,7 @@ OPDEF(line, 66, Op1, Void) // source line number for debug symbols
OPDEF(xbarrier, 67, Op2, Void) // memory barrier; doesn't exit, but flushes all values to the stack
OPDEF(xtbl, 68, Op2, Void) // exit via indirect jump
OPDEF(__69, 69, None, Void)
OPDEF(qlive, 69, Op1, Void) // extend live range of a 64-bit integer
OPDEF(__70, 70, None, Void)
OPDEF(qaddp, 71, Op2, I64) // integer addition for temp pointer calculations (64bit only)
OPDEF(qparam, 72, P, I64) // load a parameter (64bit register or stk location)
@ -201,17 +201,17 @@ OPDEF(ldq, 74, Ld, I64) // 64-bit integer load
OPDEF(qalloc, 75, I, I64) // allocate some stack space (value is 64bit address)
OPDEF(stqi, 76, Sti, Void) // 64-bit integer store
OPDEF(fret, 77, Op1, Void) // return a 64-bit float
OPDEF(st32f, 78, Sti, Void) // store 64-bit float as a 32-bit float (dropping precision)
OPDEF(ld32f, 79, Ld, F64) // load 32-bit float and widen to 64-bit float
OPDEF(st32f, 77, Sti, Void) // store 64-bit float as a 32-bit float (dropping precision)
OPDEF(ld32f, 78, Ld, F64) // load 32-bit float and widen to 64-bit float
OPDEF(fcall, 80, C, F64) // subroutine call returning 64-bit (quad) double value
OPDEF(qcall, 81, C, I64) // subroutine call returning 64-bit (quad) integer value
OPDEF(fcall, 79, C, F64) // subroutine call returning 64-bit (quad) double value
OPDEF(qcall, 80, C, I64) // subroutine call returning 64-bit (quad) integer value
OPDEF(stfi, 82, Sti, Void) // 64-bit float store
OPDEF(stfi, 81, Sti, Void) // 64-bit float store
OPDEF(__83, 83, None, Void)
OPDEF(fret, 82, Op1, Void) // return a 64-bit float
OPDEF(qret, 83, Op1, Void) // return a 64-bit integer
OPDEF(__84, 84, None, Void)
OPDEF(__85, 85, None, Void)
OPDEF(__86, 86, None, Void)
@ -256,7 +256,7 @@ OPDEF(qiadd, 112, Op2, I64) // 64-bit bitwise ADD
OPDEF(ldc32f, 113, Ld, F64) // non-volatile load 32-bit float and widen to 64-bit float
OPDEF(qjoin, 114, Op2, F64) // join two 32-bit values (1st arg is low bits, 2nd is high)
OPDEF(__115, 115, None, Void)
OPDEF(q2i, 115, Op1, I32) // truncate i64 to i32
OPDEF(__116, 116, None, Void)
OPDEF(__117, 117, None, Void)
OPDEF(float, 118, N64, F64) // 64-bit float constant value

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

@ -2754,13 +2754,15 @@ Assembler::asm_ret(LIns *ins)
}
void
Assembler::asm_promote(LIns *ins)
Assembler::asm_q2i(LIns *)
{
/* The LIR opcodes that result in a call to asm_promote are only generated
* if NANOJIT_64BIT is #define'd, which it never is for ARM.
*/
(void)ins;
NanoAssert(0);
NanoAssert(0); // q2i shouldn't occur on 32-bit platforms
}
void
Assembler::asm_promote(LIns *)
{
NanoAssert(0); // i2q and u2q shouldn't occur on 32-bit platforms
}
void

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

@ -637,7 +637,7 @@ namespace nanojit
releaseRegisters();
assignSavedRegs();
LIns *value = ins->oprnd1();
Register r = ins->isop(LIR_ret) ? R3 : F1;
Register r = ins->isop(LIR_fret) ? F1 : R3;
findSpecificRegFor(value, r);
}
@ -1036,6 +1036,13 @@ namespace nanojit
NanoAssertMsg(0, "NJ_F2I_SUPPORTED not yet supported for this architecture");
}
// XXX: this is sub-optimal, see https://bugzilla.mozilla.org/show_bug.cgi?id=540368#c7.
void Assembler::asm_q2i(LIns *ins) {
Register rr = deprecated_prepResultReg(ins, GpRegs);
int d = findMemFor(ins->oprnd1());
LWZ(rr, d+4, FP);
}
void Assembler::asm_promote(LIns *ins) {
LOpcode op = ins->opcode();
Register r = deprecated_prepResultReg(ins, GpRegs);

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

@ -1075,13 +1075,17 @@ namespace nanojit
if (ins->isop(LIR_ret)) {
findSpecificRegFor(val, retRegs[0]);
} else {
NanoAssert(ins->isop(LIR_fret));
findSpecificRegFor(val, F0);
}
}
void Assembler::asm_q2i(LIns *) {
NanoAssert(0); // q2i shouldn't occur on 32-bit platforms
}
void Assembler::asm_promote(LIns *) {
// i2q or u2q
TODO(asm_promote);
NanoAssert(0); // i2q and u2q shouldn't occur on 32-bit platforms
}
void Assembler::swapCodeChunks() {

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

@ -61,8 +61,6 @@ better code
- stack based LIR_param
tracing
- asm_qjoin
- asm_qhi
- nFragExit
*/
@ -979,6 +977,13 @@ namespace nanojit
}
}
void Assembler::asm_q2i(LIns *ins) {
Register rr, ra;
regalloc_unary(ins, GpRegs, rr, ra);
NanoAssert(IsGpReg(ra));
MOVLR(rr, ra); // 32bit mov zeros the upper 32bits of the target
}
void Assembler::asm_promote(LIns *ins) {
Register rr, ra;
regalloc_unary(ins, GpRegs, rr, ra);
@ -1366,7 +1371,7 @@ namespace nanojit
releaseRegisters();
assignSavedRegs();
LIns *value = ins->oprnd1();
Register r = ins->isop(LIR_ret) ? RAX : XMM0;
Register r = ins->isop(LIR_fret) ? XMM0 : RAX;
findSpecificRegFor(value, r);
}
@ -1567,7 +1572,7 @@ namespace nanojit
}
void Assembler::asm_qjoin(LIns*) {
TODO(asm_qjoin);
NanoAssert(0); // qjoin shouldn't occur on non-SoftFloat platforms
}
void Assembler::asm_param(LIns *ins) {
@ -1633,14 +1638,11 @@ namespace nanojit
}
void Assembler::asm_qhi(LIns*) {
TODO(asm_qhi);
NanoAssert(0); // qhi shouldn't occur on non-SoftFloat platforms
}
void Assembler::asm_qlo(LIns *ins) {
Register rr, ra;
regalloc_unary(ins, GpRegs, rr, ra);
NanoAssert(IsGpReg(ra));
MOVLR(rr, ra); // 32bit mov zeros the upper 32bits of the target
void Assembler::asm_qlo(LIns *) {
NanoAssert(0); // qlo shouldn't occur on non-SoftFloat platforms
}
void Assembler::asm_spill(Register rr, int d, bool /*pop*/, bool quad) {

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

@ -2088,14 +2088,18 @@ namespace nanojit
if (ins->isop(LIR_ret)) {
findSpecificRegFor(val, retRegs[0]);
} else {
NanoAssert(ins->isop(LIR_fret));
findSpecificRegFor(val, FST0);
fpu_pop();
}
}
void Assembler::asm_q2i(LIns *) {
NanoAssert(0); // q2i shouldn't occur on 32-bit platforms
}
void Assembler::asm_promote(LIns *) {
// i2q or u2q
TODO(asm_promote);
NanoAssert(0); // i2q and u2q shouldn't occur on 32-bit platforms
}
void Assembler::swapCodeChunks() {