ARM64: Avoid side-effects of constant rematerialization.

Thanks to Patrick Galizia.
master
Mike Pall 2019-02-04 23:04:48 +01:00
parent f0e865dd48
commit b33e3f2d44
1 changed files with 29 additions and 17 deletions

View File

@ -295,8 +295,10 @@ static void asm_fusexref(ASMState *as, A64Ins ai, Reg rd, IRRef ref,
} else if (asm_isk32(as, ir->op1, &ofs)) { } else if (asm_isk32(as, ir->op1, &ofs)) {
ref = ir->op2; ref = ir->op2;
} else { } else {
Reg rn = ra_alloc1(as, ir->op1, allow); Reg refk = irref_isk(ir->op1) ? ir->op1 : ir->op2;
IRIns *irr = IR(ir->op2); Reg refv = irref_isk(ir->op1) ? ir->op2 : ir->op1;
Reg rn = ra_alloc1(as, refv, allow);
IRIns *irr = IR(refk);
uint32_t m; uint32_t m;
if (irr+1 == ir && !ra_used(irr) && if (irr+1 == ir && !ra_used(irr) &&
irr->o == IR_ADD && irref_isk(irr->op2)) { irr->o == IR_ADD && irref_isk(irr->op2)) {
@ -307,7 +309,7 @@ static void asm_fusexref(ASMState *as, A64Ins ai, Reg rd, IRRef ref,
goto skipopm; goto skipopm;
} }
} }
m = asm_fuseopm(as, 0, ir->op2, rset_exclude(allow, rn)); m = asm_fuseopm(as, 0, refk, rset_exclude(allow, rn));
ofs = sizeof(GCstr); ofs = sizeof(GCstr);
skipopm: skipopm:
emit_lso(as, ai, rd, rd, ofs); emit_lso(as, ai, rd, rd, ofs);
@ -722,6 +724,7 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge)
Reg dest = ra_dest(as, ir, allow); Reg dest = ra_dest(as, ir, allow);
Reg tab = ra_alloc1(as, ir->op1, rset_clear(allow, dest)); Reg tab = ra_alloc1(as, ir->op1, rset_clear(allow, dest));
Reg key = 0, tmp = RID_TMP; Reg key = 0, tmp = RID_TMP;
Reg ftmp = RID_NONE, type = RID_NONE, scr = RID_NONE, tisnum = RID_NONE;
IRRef refkey = ir->op2; IRRef refkey = ir->op2;
IRIns *irkey = IR(refkey); IRIns *irkey = IR(refkey);
int isk = irref_isk(ir->op2); int isk = irref_isk(ir->op2);
@ -751,6 +754,28 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge)
} }
} }
/* Allocate constants early. */
if (irt_isnum(kt)) {
if (!isk) {
tisnum = ra_allock(as, LJ_TISNUM << 15, allow);
ftmp = ra_scratch(as, rset_exclude(RSET_FPR, key));
rset_clear(allow, tisnum);
}
} else if (irt_isaddr(kt)) {
if (isk) {
int64_t kk = ((int64_t)irt_toitype(irkey->t) << 47) | irkey[1].tv.u64;
scr = ra_allock(as, kk, allow);
} else {
scr = ra_scratch(as, allow);
}
rset_clear(allow, scr);
} else {
lua_assert(irt_ispri(kt) && !irt_isnil(kt));
type = ra_allock(as, ~((int64_t)~irt_toitype(ir->t) << 47), allow);
scr = ra_scratch(as, rset_clear(allow, type));
rset_clear(allow, scr);
}
/* Key not found in chain: jump to exit (if merged) or load niltv. */ /* Key not found in chain: jump to exit (if merged) or load niltv. */
l_end = emit_label(as); l_end = emit_label(as);
as->invmcp = NULL; as->invmcp = NULL;
@ -780,9 +805,6 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge)
emit_nm(as, A64I_CMPx, key, tmp); emit_nm(as, A64I_CMPx, key, tmp);
emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key.u64)); emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key.u64));
} else { } else {
Reg tisnum = ra_allock(as, LJ_TISNUM << 15, allow);
Reg ftmp = ra_scratch(as, rset_exclude(RSET_FPR, key));
rset_clear(allow, tisnum);
emit_nm(as, A64I_FCMPd, key, ftmp); emit_nm(as, A64I_FCMPd, key, ftmp);
emit_dn(as, A64I_FMOV_D_R, (ftmp & 31), (tmp & 31)); emit_dn(as, A64I_FMOV_D_R, (ftmp & 31), (tmp & 31));
emit_cond_branch(as, CC_LO, l_next); emit_cond_branch(as, CC_LO, l_next);
@ -790,31 +812,21 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge)
emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key.n)); emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key.n));
} }
} else if (irt_isaddr(kt)) { } else if (irt_isaddr(kt)) {
Reg scr;
if (isk) { if (isk) {
int64_t kk = ((int64_t)irt_toitype(irkey->t) << 47) | irkey[1].tv.u64;
scr = ra_allock(as, kk, allow);
emit_nm(as, A64I_CMPx, scr, tmp); emit_nm(as, A64I_CMPx, scr, tmp);
emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key.u64)); emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key.u64));
} else { } else {
scr = ra_scratch(as, allow);
emit_nm(as, A64I_CMPx, tmp, scr); emit_nm(as, A64I_CMPx, tmp, scr);
emit_lso(as, A64I_LDRx, scr, dest, offsetof(Node, key.u64)); emit_lso(as, A64I_LDRx, scr, dest, offsetof(Node, key.u64));
} }
rset_clear(allow, scr);
} else { } else {
Reg type, scr;
lua_assert(irt_ispri(kt) && !irt_isnil(kt));
type = ra_allock(as, ~((int64_t)~irt_toitype(ir->t) << 47), allow);
scr = ra_scratch(as, rset_clear(allow, type));
rset_clear(allow, scr);
emit_nm(as, A64I_CMPw, scr, type); emit_nm(as, A64I_CMPw, scr, type);
emit_lso(as, A64I_LDRx, scr, dest, offsetof(Node, key)); emit_lso(as, A64I_LDRx, scr, dest, offsetof(Node, key));
} }
*l_loop = A64I_BCC | A64F_S19(as->mcp - l_loop) | CC_NE; *l_loop = A64I_BCC | A64F_S19(as->mcp - l_loop) | CC_NE;
if (!isk && irt_isaddr(kt)) { if (!isk && irt_isaddr(kt)) {
Reg type = ra_allock(as, (int32_t)irt_toitype(kt), allow); type = ra_allock(as, (int32_t)irt_toitype(kt), allow);
emit_dnm(as, A64I_ADDx | A64F_SH(A64SH_LSL, 47), tmp, key, type); emit_dnm(as, A64I_ADDx | A64F_SH(A64SH_LSL, 47), tmp, key, type);
rset_clear(allow, type); rset_clear(allow, type);
} }