Skip to content

Commit

Permalink
tcg/arm: Simplify usage of encode_imm
Browse files Browse the repository at this point in the history
We have already computed the rotated value of the imm8
portion of the complete imm12 encoding.  No sense leaving
the combination of rot + rotation to the caller.

Create an encode_imm12_nofail helper that performs an assert.

This removes the final use of the local "rotl" function,
which duplicated our generic "rol32" function.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
  • Loading branch information
rth7680 committed Sep 14, 2021
1 parent 68c6cd1 commit 8067a77
Showing 1 changed file with 77 additions and 64 deletions.
141 changes: 77 additions & 64 deletions tcg/arm/tcg-target.c.inc
Expand Up @@ -312,10 +312,10 @@ static bool reloc_pc8(tcg_insn_unit *src_rw, const tcg_insn_unit *target)
{
const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw);
ptrdiff_t offset = tcg_ptr_byte_diff(target, src_rx) - 8;
int rot = encode_imm(offset);
int imm12 = encode_imm(offset);

if (rot >= 0) {
*src_rw = deposit32(*src_rw, 0, 12, rol32(offset, rot) | (rot << 7));
if (imm12 >= 0) {
*src_rw = deposit32(*src_rw, 0, 12, imm12);
return true;
}
return false;
Expand Down Expand Up @@ -369,33 +369,52 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
(ALL_GENERAL_REGS & ~((1 << TCG_REG_R0) | (1 << TCG_REG_R1)))
#endif

static inline uint32_t rotl(uint32_t val, int n)
{
return (val << n) | (val >> (32 - n));
}

/* ARM immediates for ALU instructions are made of an unsigned 8-bit
right-rotated by an even amount between 0 and 30. */
/*
* ARM immediates for ALU instructions are made of an unsigned 8-bit
* right-rotated by an even amount between 0 and 30.
*
* Return < 0 if @imm cannot be encoded, else the entire imm12 field.
*/
static int encode_imm(uint32_t imm)
{
int shift;
uint32_t rot, imm8;

/* simple case, only lower bits */
if ((imm & ~0xff) == 0)
return 0;
/* then try a simple even shift */
shift = ctz32(imm) & ~1;
if (((imm >> shift) & ~0xff) == 0)
return 32 - shift;
/* now try harder with rotations */
if ((rotl(imm, 2) & ~0xff) == 0)
return 2;
if ((rotl(imm, 4) & ~0xff) == 0)
return 4;
if ((rotl(imm, 6) & ~0xff) == 0)
return 6;
/* imm can't be encoded */
/* Simple case, no rotation required. */
if ((imm & ~0xff) == 0) {
return imm;
}

/* Next, try a simple even shift. */
rot = ctz32(imm) & ~1;
imm8 = imm >> rot;
rot = 32 - rot;
if ((imm8 & ~0xff) == 0) {
goto found;
}

/*
* Finally, try harder with rotations.
* The ctz test above will have taken care of rotates >= 8.
*/
for (rot = 2; rot < 8; rot += 2) {
imm8 = rol32(imm, rot);
if ((imm8 & ~0xff) == 0) {
goto found;
}
}
/* Fail: imm cannot be encoded. */
return -1;

found:
/* Note that rot is even, and we discard bit 0 by shifting by 7. */
return rot << 7 | imm8;
}

static int encode_imm_nofail(uint32_t imm)
{
int ret = encode_imm(imm);
tcg_debug_assert(ret >= 0);
return ret;
}

static inline int check_fit_imm(uint32_t imm)
Expand Down Expand Up @@ -782,38 +801,34 @@ static void tcg_out_movi_pool(TCGContext *s, int cond, int rd, uint32_t arg)

static void tcg_out_movi32(TCGContext *s, int cond, int rd, uint32_t arg)
{
int rot, diff, opc, sh1, sh2;
int imm12, diff, opc, sh1, sh2;
uint32_t tt0, tt1, tt2;

/* Check a single MOV/MVN before anything else. */
rot = encode_imm(arg);
if (rot >= 0) {
tcg_out_dat_imm(s, cond, ARITH_MOV, rd, 0,
rotl(arg, rot) | (rot << 7));
imm12 = encode_imm(arg);
if (imm12 >= 0) {
tcg_out_dat_imm(s, cond, ARITH_MOV, rd, 0, imm12);
return;
}
rot = encode_imm(~arg);
if (rot >= 0) {
tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0,
rotl(~arg, rot) | (rot << 7));
imm12 = encode_imm(~arg);
if (imm12 >= 0) {
tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, imm12);
return;
}

/* Check for a pc-relative address. This will usually be the TB,
or within the TB, which is immediately before the code block. */
diff = tcg_pcrel_diff(s, (void *)arg) - 8;
if (diff >= 0) {
rot = encode_imm(diff);
if (rot >= 0) {
tcg_out_dat_imm(s, cond, ARITH_ADD, rd, TCG_REG_PC,
rotl(diff, rot) | (rot << 7));
imm12 = encode_imm(diff);
if (imm12 >= 0) {
tcg_out_dat_imm(s, cond, ARITH_ADD, rd, TCG_REG_PC, imm12);
return;
}
} else {
rot = encode_imm(-diff);
if (rot >= 0) {
tcg_out_dat_imm(s, cond, ARITH_SUB, rd, TCG_REG_PC,
rotl(-diff, rot) | (rot << 7));
imm12 = encode_imm(-diff);
if (imm12 >= 0) {
tcg_out_dat_imm(s, cond, ARITH_SUB, rd, TCG_REG_PC, imm12);
return;
}
}
Expand Down Expand Up @@ -845,6 +860,8 @@ static void tcg_out_movi32(TCGContext *s, int cond, int rd, uint32_t arg)
sh2 = ctz32(tt1) & ~1;
tt2 = tt1 & ~(0xff << sh2);
if (tt2 == 0) {
int rot;

rot = ((32 - sh1) << 7) & 0xf00;
tcg_out_dat_imm(s, cond, opc, rd, 0, ((tt0 >> sh1) & 0xff) | rot);
rot = ((32 - sh2) << 7) & 0xf00;
Expand All @@ -857,37 +874,35 @@ static void tcg_out_movi32(TCGContext *s, int cond, int rd, uint32_t arg)
tcg_out_movi_pool(s, cond, rd, arg);
}

/*
* Emit either the reg,imm or reg,reg form of a data-processing insn.
* rhs must satisfy the "rI" constraint.
*/
static inline void tcg_out_dat_rI(TCGContext *s, int cond, int opc, TCGArg dst,
TCGArg lhs, TCGArg rhs, int rhs_is_const)
{
/* Emit either the reg,imm or reg,reg form of a data-processing insn.
* rhs must satisfy the "rI" constraint.
*/
if (rhs_is_const) {
int rot = encode_imm(rhs);
tcg_debug_assert(rot >= 0);
tcg_out_dat_imm(s, cond, opc, dst, lhs, rotl(rhs, rot) | (rot << 7));
tcg_out_dat_imm(s, cond, opc, dst, lhs, encode_imm_nofail(rhs));
} else {
tcg_out_dat_reg(s, cond, opc, dst, lhs, rhs, SHIFT_IMM_LSL(0));
}
}

/*
* Emit either the reg,imm or reg,reg form of a data-processing insn.
* rhs must satisfy the "rIK" constraint.
*/
static void tcg_out_dat_rIK(TCGContext *s, int cond, int opc, int opinv,
TCGReg dst, TCGReg lhs, TCGArg rhs,
bool rhs_is_const)
{
/* Emit either the reg,imm or reg,reg form of a data-processing insn.
* rhs must satisfy the "rIK" constraint.
*/
if (rhs_is_const) {
int rot = encode_imm(rhs);
if (rot < 0) {
rhs = ~rhs;
rot = encode_imm(rhs);
tcg_debug_assert(rot >= 0);
int imm12 = encode_imm(rhs);
if (imm12 < 0) {
imm12 = encode_imm_nofail(~rhs);
opc = opinv;
}
tcg_out_dat_imm(s, cond, opc, dst, lhs, rotl(rhs, rot) | (rot << 7));
tcg_out_dat_imm(s, cond, opc, dst, lhs, imm12);
} else {
tcg_out_dat_reg(s, cond, opc, dst, lhs, rhs, SHIFT_IMM_LSL(0));
}
Expand All @@ -901,14 +916,12 @@ static void tcg_out_dat_rIN(TCGContext *s, int cond, int opc, int opneg,
* rhs must satisfy the "rIN" constraint.
*/
if (rhs_is_const) {
int rot = encode_imm(rhs);
if (rot < 0) {
rhs = -rhs;
rot = encode_imm(rhs);
tcg_debug_assert(rot >= 0);
int imm12 = encode_imm(rhs);
if (imm12 < 0) {
imm12 = encode_imm_nofail(-rhs);
opc = opneg;
}
tcg_out_dat_imm(s, cond, opc, dst, lhs, rotl(rhs, rot) | (rot << 7));
tcg_out_dat_imm(s, cond, opc, dst, lhs, imm12);
} else {
tcg_out_dat_reg(s, cond, opc, dst, lhs, rhs, SHIFT_IMM_LSL(0));
}
Expand Down

0 comments on commit 8067a77

Please sign in to comment.