ARM64: Improve generation of immediates.

This commit is contained in:
Mike Pall 2021-03-23 02:08:44 +01:00
parent a4c9fc3d6c
commit ebc4919aff

View File

@ -194,10 +194,6 @@ static int emit_kdelta(ASMState *as, Reg rd, uint64_t k, int lim)
static void emit_loadk(ASMState *as, Reg rd, uint64_t u64, int is64)
{
uint32_t k13 = emit_isk13(u64, is64);
if (k13) { /* Can the constant be represented as a bitmask immediate? */
emit_dn(as, (is64|A64I_ORRw)^k13, rd, RID_ZERO);
} else {
int i, zeros = 0, ones = 0, neg;
if (!is64) u64 = (int64_t)(int32_t)u64; /* Sign-extend. */
/* Count homogeneous 16 bit fragments. */
@ -207,6 +203,13 @@ static void emit_loadk(ASMState *as, Reg rd, uint64_t u64, int is64)
ones += (frag == 0xffff);
}
neg = ones > zeros; /* Use MOVN if it pays off. */
if ((neg ? ones : zeros) < 3) { /* Need 2+ ins. Try shorter K13 encoding. */
uint32_t k13 = emit_isk13(u64, is64);
if (k13) {
emit_dn(as, (is64|A64I_ORRw)^k13, rd, RID_ZERO);
return;
}
}
if (!emit_kdelta(as, rd, u64, 4 - (neg ? ones : zeros))) {
int shift = 0, lshift = 0;
uint64_t n64 = neg ? ~u64 : u64;
@ -227,7 +230,6 @@ static void emit_loadk(ASMState *as, Reg rd, uint64_t u64, int is64)
emit_d(as, (neg ? A64I_MOVNx : A64I_MOVZx) |
A64F_U16((n64 >> lshift) & 0xffff) | A64F_LSL16(lshift), rd);
}
}
}
/* Load a 32 bit constant into a GPR. */