summaryrefslogtreecommitdiffstats
path: root/tcg/arm
diff options
context:
space:
mode:
authorRichard Henderson2021-08-10 00:27:08 +0200
committerRichard Henderson2021-09-14 21:00:21 +0200
commit90606715dc1b5de5c432afd0deac8b5c6d36eeda (patch)
tree57ddb8f177658e23add26db054baf0447458969c /tcg/arm
parenttcg/arm: Split out tcg_out_ldstm (diff)
downloadqemu-90606715dc1b5de5c432afd0deac8b5c6d36eeda.tar.gz
qemu-90606715dc1b5de5c432afd0deac8b5c6d36eeda.tar.xz
qemu-90606715dc1b5de5c432afd0deac8b5c6d36eeda.zip
tcg/arm: Simplify usage of encode_imm
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>
Diffstat (limited to 'tcg/arm')
-rw-r--r--tcg/arm/tcg-target.c.inc141
1 files changed, 77 insertions, 64 deletions
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
index c9e3fcfeac..1931cea1ca 100644
--- a/tcg/arm/tcg-target.c.inc
+++ b/tcg/arm/tcg-target.c.inc
@@ -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;
@@ -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)
@@ -782,20 +801,18 @@ 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;
}
@@ -803,17 +820,15 @@ static void tcg_out_movi32(TCGContext *s, int cond, int rd, uint32_t arg)
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;
}
}
@@ -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;
@@ -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));
}
@@ -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));
}