target/arm: Convert packing, unpacking, saturation, and reversal

Backports commit 46497f6af73bb33c1064d43a28a48cbb4d233a23 from qemu
This commit is contained in:
Richard Henderson 2019-11-19 23:43:10 -05:00 committed by Lioncash
parent 83cced6170
commit 987641cf10
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
3 changed files with 376 additions and 309 deletions

View file

@ -28,6 +28,7 @@
&s_rri_rot s rn rd imm rot
&s_rrrr s rd rn rm ra
&rrrr rd rn rm ra
&rrr_rot rd rn rm rot
&rrr rd rn rm
&rr rd rm
&ri rd imm
@ -43,6 +44,8 @@
&ldrex rn rt rt2 imm
&bfx rd rn lsb widthm1
&bfi rd rn lsb msb
&sat rd rn satimm imm sh
&pkh rd rn rm imm tb
# Data-processing (register)
@ -454,3 +457,32 @@ UHSAX .... 0110 0111 .... .... 1111 0101 .... @rndm
UHSUB16 .... 0110 0111 .... .... 1111 0111 .... @rndm
UHADD8 .... 0110 0111 .... .... 1111 1001 .... @rndm
UHSUB8 .... 0110 0111 .... .... 1111 1111 .... @rndm
# Packing, unpacking, saturation, and reversal
PKH ---- 0110 1000 rn:4 rd:4 imm:5 tb:1 01 rm:4 &pkh
@sat ---- .... ... satimm:5 rd:4 imm:5 sh:1 .. rn:4 &sat
@sat16 ---- .... .... satimm:4 rd:4 .... .... rn:4 \
&sat imm=0 sh=0
SSAT .... 0110 101. .... .... .... ..01 .... @sat
USAT .... 0110 111. .... .... .... ..01 .... @sat
SSAT16 .... 0110 1010 .... .... 1111 0011 .... @sat16
USAT16 .... 0110 1110 .... .... 1111 0011 .... @sat16
@rrr_rot ---- .... .... rn:4 rd:4 rot:2 ...... rm:4 &rrr_rot
SXTAB16 .... 0110 1000 .... .... ..00 0111 .... @rrr_rot
SXTAB .... 0110 1010 .... .... ..00 0111 .... @rrr_rot
SXTAH .... 0110 1011 .... .... ..00 0111 .... @rrr_rot
UXTAB16 .... 0110 1100 .... .... ..00 0111 .... @rrr_rot
UXTAB .... 0110 1110 .... .... ..00 0111 .... @rrr_rot
UXTAH .... 0110 1111 .... .... ..00 0111 .... @rrr_rot
SEL .... 0110 1000 .... .... 1111 1011 .... @rndm
REV .... 0110 1011 1111 .... 1111 0011 .... @rdm
REV16 .... 0110 1011 1111 .... 1111 1011 .... @rdm
REVSH .... 0110 1111 1111 .... 1111 1011 .... @rdm
RBIT .... 0110 1111 1111 .... 1111 0011 .... @rdm

View file

@ -25,6 +25,7 @@
&s_rri_rot !extern s rn rd imm rot
&s_rrrr !extern s rd rn rm ra
&rrrr !extern rd rn rm ra
&rrr_rot !extern rd rn rm rot
&rrr !extern rd rn rm
&rr !extern rd rm
&ri !extern rd imm
@ -40,6 +41,8 @@
&ldrex !extern rn rt rt2 imm
&bfx !extern rd rn lsb widthm1
&bfi !extern rd rn lsb msb
&sat !extern rd rn satimm imm sh
&pkh !extern rd rn rm imm tb
# Data-processing (register)
@ -69,7 +72,8 @@ BIC_rrri 1110101 0001 . .... 0 ... .... .... .... @s_rrr_shi
TEQ_xrri 1110101 0100 1 .... 0 ... 1111 .... .... @S_xrr_shi
EOR_rrri 1110101 0100 . .... 0 ... .... .... .... @s_rrr_shi
}
# PKHBT, PKHTB at opc1 = 0110
PKH 1110101 0110 0 rn:4 0 ... rd:4 .. tb:1 0 rm:4 \
&pkh imm=%imm5_12_6
{
CMN_xrri 1110101 1000 1 .... 0 ... 1111 .... .... @S_xrr_shi
ADD_rrri 1110101 1000 . .... 0 ... .... .... .... @s_rrr_shi
@ -148,6 +152,20 @@ RSB_rri 1111 0.0 1110 . .... 0 ... .... ........ @s_rri_rot
# Saturate, bitfield
@sat .... .... .. sh:1 . rn:4 . ... rd:4 .. . satimm:5 \
&sat imm=%imm5_12_6
@sat16 .... .... .. . . rn:4 . ... rd:4 .. . satimm:5 \
&sat sh=0 imm=0
{
SSAT16 1111 0011 001 0 .... 0 000 .... 00 0 ..... @sat16
SSAT 1111 0011 00. 0 .... 0 ... .... .. 0 ..... @sat
}
{
USAT16 1111 0011 101 0 .... 0 000 .... 00 0 ..... @sat16
USAT 1111 0011 10. 0 .... 0 ... .... .. 0 ..... @sat
}
@bfx .... .... ... . rn:4 . ... rd:4 .. . widthm1:5 \
&bfx lsb=%imm5_12_6
@bfi .... .... ... . rn:4 . ... rd:4 .. . msb:5 \
@ -224,7 +242,13 @@ CRC32CB 1111 1010 1101 .... 1111 .... 1000 .... @rndm
CRC32CH 1111 1010 1101 .... 1111 .... 1001 .... @rndm
CRC32CW 1111 1010 1101 .... 1111 .... 1010 .... @rndm
SEL 1111 1010 1010 .... 1111 .... 1000 .... @rndm
# Note rn != rm is CONSTRAINED UNPREDICTABLE; we choose to ignore rn.
REV 1111 1010 1001 ---- 1111 .... 1000 .... @rdm
REV16 1111 1010 1001 ---- 1111 .... 1001 .... @rdm
RBIT 1111 1010 1001 ---- 1111 .... 1010 .... @rdm
REVSH 1111 1010 1001 ---- 1111 .... 1011 .... @rdm
CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm
# Branches and miscellaneous control
@ -501,3 +525,14 @@ SHSAX 1111 1010 1110 .... 1111 .... 0010 .... @rndm
USAX 1111 1010 1110 .... 1111 .... 0100 .... @rndm
UQSAX 1111 1010 1110 .... 1111 .... 0101 .... @rndm
UHSAX 1111 1010 1110 .... 1111 .... 0110 .... @rndm
# Register extends
@rrr_rot .... .... .... rn:4 .... rd:4 .. rot:2 rm:4 &rrr_rot
SXTAH 1111 1010 0000 .... 1111 .... 10.. .... @rrr_rot
UXTAH 1111 1010 0001 .... 1111 .... 10.. .... @rrr_rot
SXTAB16 1111 1010 0010 .... 1111 .... 10.. .... @rrr_rot
UXTAB16 1111 1010 0011 .... 1111 .... 10.. .... @rrr_rot
SXTAB 1111 1010 0100 .... 1111 .... 10.. .... @rrr_rot
UXTAB 1111 1010 0101 .... 1111 .... 10.. .... @rrr_rot

View file

@ -361,7 +361,7 @@ static void gen_smul_dual(DisasContext *s, TCGv_i32 a, TCGv_i32 b)
}
/* Byteswap each halfword. */
static void gen_rev16(DisasContext *s, TCGv_i32 var)
static void gen_rev16(DisasContext *s, TCGv_i32 dest, TCGv_i32 var)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
TCGv_i32 tmp = tcg_temp_new_i32(tcg_ctx);
@ -370,18 +370,18 @@ static void gen_rev16(DisasContext *s, TCGv_i32 var)
tcg_gen_and_i32(tcg_ctx, tmp, tmp, mask);
tcg_gen_and_i32(tcg_ctx, var, var, mask);
tcg_gen_shli_i32(tcg_ctx, var, var, 8);
tcg_gen_or_i32(tcg_ctx, var, var, tmp);
tcg_gen_or_i32(tcg_ctx, dest, var, tmp);
tcg_temp_free_i32(tcg_ctx, mask);
tcg_temp_free_i32(tcg_ctx, tmp);
}
/* Byteswap low halfword and sign extend. */
static void gen_revsh(DisasContext *s, TCGv_i32 var)
static void gen_revsh(DisasContext *s, TCGv_i32 dest, TCGv_i32 var)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
tcg_gen_ext16u_i32(tcg_ctx, var, var);
tcg_gen_bswap16_i32(tcg_ctx, var, var);
tcg_gen_ext16s_i32(tcg_ctx, var, var);
tcg_gen_ext16s_i32(tcg_ctx, dest, var);
}
/* 32x32->64 multiply. Marks inputs as dead. */
@ -437,7 +437,7 @@ static void gen_swap_half(DisasContext *s, TCGv_i32 var)
t0 = (t0 + t1) ^ tmp;
*/
static void gen_add16(DisasContext *s, TCGv_i32 t0, TCGv_i32 t1)
static void gen_add16(DisasContext *s, TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
TCGv_i32 tmp = tcg_temp_new_i32(tcg_ctx);
@ -446,9 +446,8 @@ static void gen_add16(DisasContext *s, TCGv_i32 t0, TCGv_i32 t1)
tcg_gen_andi_i32(tcg_ctx, t0, t0, ~0x8000);
tcg_gen_andi_i32(tcg_ctx, t1, t1, ~0x8000);
tcg_gen_add_i32(tcg_ctx, t0, t0, t1);
tcg_gen_xor_i32(tcg_ctx, t0, t0, tmp);
tcg_gen_xor_i32(tcg_ctx, dest, t0, tmp);
tcg_temp_free_i32(tcg_ctx, tmp);
tcg_temp_free_i32(tcg_ctx, t1);
}
/* Set N and Z flags from var. */
@ -6490,7 +6489,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
}
break;
case NEON_2RM_VREV16:
gen_rev16(s, tmp);
gen_rev16(s, tmp, tmp);
break;
case NEON_2RM_VCLS:
switch (size) {
@ -7780,6 +7779,78 @@ static void gen_xor_i32(DisasContext *s, TCGv_i32 dest, TCGv_i32 a, TCGv_i32 b)
tcg_gen_xor_i32(tcg_ctx, dest, a, b);
}
static void gen_ext8s_i32(DisasContext *s, TCGv_i32 dest, TCGv_i32 src)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
tcg_gen_ext8s_i32(tcg_ctx, dest, src);
}
static void gen_ext16s_i32(DisasContext *s, TCGv_i32 dest, TCGv_i32 src)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
tcg_gen_ext16s_i32(tcg_ctx, dest, src);
}
static void gen_ext8u_i32(DisasContext *s, TCGv_i32 dest, TCGv_i32 src)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
tcg_gen_ext8u_i32(tcg_ctx, dest, src);
}
static void gen_ext16u_i32(DisasContext *s, TCGv_i32 dest, TCGv_i32 src)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
tcg_gen_ext16u_i32(tcg_ctx, dest, src);
}
static void gen_bswap32_i32(DisasContext *s, TCGv_i32 dest, TCGv_i32 src)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
tcg_gen_bswap32_i32(tcg_ctx, dest, src);
}
static void gen_ssat_dectree(DisasContext *s, TCGv_i32 dest, TCGv_env env, TCGv_i32 a, TCGv_i32 b)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
gen_helper_ssat(tcg_ctx, dest, env, a, b);
}
static void gen_usat_dectree(DisasContext *s, TCGv_i32 dest, TCGv_env env, TCGv_i32 a, TCGv_i32 b)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
gen_helper_usat(tcg_ctx, dest, env, a, b);
}
static void gen_ssat16_dectree(DisasContext *s, TCGv_i32 dest, TCGv_env env, TCGv_i32 a, TCGv_i32 b)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
gen_helper_ssat16(tcg_ctx, dest, env, a, b);
}
static void gen_usat16_dectree(DisasContext *s, TCGv_i32 dest, TCGv_env env, TCGv_i32 a, TCGv_i32 b)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
gen_helper_usat16(tcg_ctx, dest, env, a, b);
}
static void gen_sxtb16_dectree(DisasContext *s, TCGv_i32 dest, TCGv_i32 src)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
gen_helper_sxtb16(tcg_ctx, dest, src);
}
static void gen_uxtb16_dectree(DisasContext *s, TCGv_i32 dest, TCGv_i32 src)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
gen_helper_uxtb16(tcg_ctx, dest, src);
}
static void gen_rbit_dectree(DisasContext* s, TCGv_i32 dest, TCGv_i32 src)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
gen_helper_rbit(tcg_ctx, dest, src);
}
/*
* Helpers for the data processing routines.
*
@ -9580,6 +9651,222 @@ DO_PAR_ADDSUB(UHSUB8, gen_helper_uhsub8)
#undef DO_PAR_ADDSUB
#undef DO_PAR_ADDSUB_GE
/*
* Packing, unpacking, saturation, and reversal
*/
static bool trans_PKH(DisasContext *s, arg_PKH *a)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
TCGv_i32 tn, tm;
int shift = a->imm;
if (s->thumb
? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
: !ENABLE_ARCH_6) {
return false;
}
tn = load_reg(s, a->rn);
tm = load_reg(s, a->rm);
if (a->tb) {
/* PKHTB */
if (shift == 0) {
shift = 31;
}
tcg_gen_sari_i32(tcg_ctx, tm, tm, shift);
tcg_gen_deposit_i32(tcg_ctx, tn, tn, tm, 0, 16);
} else {
/* PKHBT */
tcg_gen_shli_i32(tcg_ctx, tm, tm, shift);
tcg_gen_deposit_i32(tcg_ctx, tn, tm, tn, 0, 16);
}
tcg_temp_free_i32(tcg_ctx, tm);
store_reg(s, a->rd, tn);
return true;
}
static bool op_sat(DisasContext *s, arg_sat *a,
void (*gen)(DisasContext *, TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
TCGv_i32 tmp, satimm;
int shift = a->imm;
if (!ENABLE_ARCH_6) {
return false;
}
tmp = load_reg(s, a->rn);
if (a->sh) {
tcg_gen_sari_i32(tcg_ctx, tmp, tmp, shift ? shift : 31);
} else {
tcg_gen_shli_i32(tcg_ctx, tmp, tmp, shift);
}
satimm = tcg_const_i32(tcg_ctx, a->satimm);
gen(s, tmp, tcg_ctx->cpu_env, tmp, satimm);
tcg_temp_free_i32(tcg_ctx, satimm);
store_reg(s, a->rd, tmp);
return true;
}
static bool trans_SSAT(DisasContext *s, arg_sat *a)
{
return op_sat(s, a, gen_ssat_dectree);
}
static bool trans_USAT(DisasContext *s, arg_sat *a)
{
return op_sat(s, a, gen_usat_dectree);
}
static bool trans_SSAT16(DisasContext *s, arg_sat *a)
{
if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
return false;
}
return op_sat(s, a, gen_ssat16_dectree);
}
static bool trans_USAT16(DisasContext *s, arg_sat *a)
{
if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
return false;
}
return op_sat(s, a, gen_usat16_dectree);
}
static bool op_xta(DisasContext *s, arg_rrr_rot *a,
void (*gen_extract)(DisasContext *, TCGv_i32, TCGv_i32),
void (*gen_add)(DisasContext*, TCGv_i32, TCGv_i32, TCGv_i32))
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
TCGv_i32 tmp;
if (!ENABLE_ARCH_6) {
return false;
}
tmp = load_reg(s, a->rm);
/*
* TODO: In many cases we could do a shift instead of a rotate.
* Combined with a simple extend, that becomes an extract.
*/
tcg_gen_rotri_i32(tcg_ctx, tmp, tmp, a->rot * 8);
gen_extract(s, tmp, tmp);
if (a->rn != 15) {
TCGv_i32 tmp2 = load_reg(s, a->rn);
gen_add(s, tmp, tmp, tmp2);
tcg_temp_free_i32(tcg_ctx, tmp2);
}
store_reg(s, a->rd, tmp);
return true;
}
static bool trans_SXTAB(DisasContext *s, arg_rrr_rot *a)
{
return op_xta(s, a, gen_ext8s_i32, gen_add_i32);
}
static bool trans_SXTAH(DisasContext *s, arg_rrr_rot *a)
{
return op_xta(s, a, gen_ext16s_i32, gen_add_i32);
}
static bool trans_SXTAB16(DisasContext *s, arg_rrr_rot *a)
{
if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
return false;
}
return op_xta(s, a, gen_sxtb16_dectree, gen_add16);
}
static bool trans_UXTAB(DisasContext *s, arg_rrr_rot *a)
{
return op_xta(s, a, gen_ext8u_i32, gen_add_i32);
}
static bool trans_UXTAH(DisasContext *s, arg_rrr_rot *a)
{
return op_xta(s, a, gen_ext16u_i32, gen_add_i32);
}
static bool trans_UXTAB16(DisasContext *s, arg_rrr_rot *a)
{
if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
return false;
}
return op_xta(s, a, gen_uxtb16_dectree, gen_add16);
}
static bool trans_SEL(DisasContext *s, arg_rrr *a)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
TCGv_i32 t1, t2, t3;
if (s->thumb
? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
: !ENABLE_ARCH_6) {
return false;
}
t1 = load_reg(s, a->rn);
t2 = load_reg(s, a->rm);
t3 = tcg_temp_new_i32(tcg_ctx);
tcg_gen_ld_i32(tcg_ctx, t3, tcg_ctx->cpu_env, offsetof(CPUARMState, GE));
gen_helper_sel_flags(tcg_ctx, t1, t3, t1, t2);
tcg_temp_free_i32(tcg_ctx, t3);
tcg_temp_free_i32(tcg_ctx, t2);
store_reg(s, a->rd, t1);
return true;
}
static bool op_rr(DisasContext *s, arg_rr *a,
void (*gen)(DisasContext* s, TCGv_i32, TCGv_i32))
{
TCGv_i32 tmp;
tmp = load_reg(s, a->rm);
gen(s, tmp, tmp);
store_reg(s, a->rd, tmp);
return true;
}
static bool trans_REV(DisasContext *s, arg_rr *a)
{
if (!ENABLE_ARCH_6) {
return false;
}
return op_rr(s, a, gen_bswap32_i32);
}
static bool trans_REV16(DisasContext *s, arg_rr *a)
{
if (!ENABLE_ARCH_6) {
return false;
}
return op_rr(s, a, gen_rev16);
}
static bool trans_REVSH(DisasContext *s, arg_rr *a)
{
if (!ENABLE_ARCH_6) {
return false;
}
return op_rr(s, a, gen_revsh);
}
static bool trans_RBIT(DisasContext *s, arg_rr *a)
{
if (!ENABLE_ARCH_6T2) {
return false;
}
return op_rr(s, a, gen_rbit_dectree);
}
/*
* Legacy decoder.
*/
@ -9587,7 +9874,7 @@ DO_PAR_ADDSUB(UHSUB8, gen_helper_uhsub8)
static void disas_arm_insn(DisasContext *s, unsigned int insn)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
unsigned int cond, val, op1, i, shift, rm, rs, rn, rd, sh;
unsigned int cond, val, op1, i, rm, rs, rn, rd;
TCGv_i32 tmp;
TCGv_i32 tmp2;
TCGv_i32 tmp3;
@ -9902,112 +10189,9 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
/* Done by decodetree */
goto illegal_op;
case 1:
if ((insn & 0x00700020) == 0) {
/* Halfword pack. */
tmp = load_reg(s, rn);
tmp2 = load_reg(s, rm);
shift = (insn >> 7) & 0x1f;
if (insn & (1 << 6)) {
/* pkhtb */
if (shift == 0) {
shift = 31;
}
tcg_gen_sari_i32(tcg_ctx, tmp2, tmp2, shift);
tcg_gen_deposit_i32(tcg_ctx, tmp, tmp, tmp2, 0, 16);
} else {
/* pkhbt */
tcg_gen_shli_i32(tcg_ctx, tmp2, tmp2, shift);
tcg_gen_deposit_i32(tcg_ctx, tmp, tmp2, tmp, 0, 16);
}
tcg_temp_free_i32(tcg_ctx, tmp2);
store_reg(s, rd, tmp);
} else if ((insn & 0x00200020) == 0x00200000) {
/* [us]sat */
tmp = load_reg(s, rm);
shift = (insn >> 7) & 0x1f;
if (insn & (1 << 6)) {
if (shift == 0)
shift = 31;
tcg_gen_sari_i32(tcg_ctx, tmp, tmp, shift);
} else {
tcg_gen_shli_i32(tcg_ctx, tmp, tmp, shift);
}
sh = (insn >> 16) & 0x1f;
tmp2 = tcg_const_i32(tcg_ctx, sh);
if (insn & (1 << 22))
gen_helper_usat(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
else
gen_helper_ssat(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
tcg_temp_free_i32(tcg_ctx, tmp2);
store_reg(s, rd, tmp);
} else if ((insn & 0x00300fe0) == 0x00200f20) {
/* [us]sat16 */
tmp = load_reg(s, rm);
sh = (insn >> 16) & 0x1f;
tmp2 = tcg_const_i32(tcg_ctx, sh);
if (insn & (1 << 22))
gen_helper_usat16(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
else
gen_helper_ssat16(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
tcg_temp_free_i32(tcg_ctx, tmp2);
store_reg(s, rd, tmp);
} else if ((insn & 0x00700fe0) == 0x00000fa0) {
/* Select bytes. */
tmp = load_reg(s, rn);
tmp2 = load_reg(s, rm);
tmp3 = tcg_temp_new_i32(tcg_ctx);
tcg_gen_ld_i32(tcg_ctx, tmp3, tcg_ctx->cpu_env, offsetof(CPUARMState, GE));
gen_helper_sel_flags(tcg_ctx, tmp, tmp3, tmp, tmp2);
tcg_temp_free_i32(tcg_ctx, tmp3);
tcg_temp_free_i32(tcg_ctx, tmp2);
store_reg(s, rd, tmp);
} else if ((insn & 0x000003e0) == 0x00000060) {
tmp = load_reg(s, rm);
shift = (insn >> 10) & 3;
/* ??? In many cases it's not necessary to do a
rotate, a shift is sufficient. */
tcg_gen_rotri_i32(tcg_ctx, tmp, tmp, shift * 8);
op1 = (insn >> 20) & 7;
switch (op1) {
case 0: gen_sxtb16(tmp); break;
case 2: gen_sxtb(tmp); break;
case 3: gen_sxth(tmp); break;
case 4: gen_uxtb16(tmp); break;
case 6: gen_uxtb(tmp); break;
case 7: gen_uxth(tmp); break;
default: goto illegal_op;
}
if (rn != 15) {
tmp2 = load_reg(s, rn);
if ((op1 & 3) == 0) {
gen_add16(s, tmp, tmp2);
} else {
tcg_gen_add_i32(tcg_ctx, tmp, tmp, tmp2);
tcg_temp_free_i32(tcg_ctx, tmp2);
}
}
store_reg(s, rd, tmp);
} else if ((insn & 0x003f0f60) == 0x003f0f20) {
/* rev */
tmp = load_reg(s, rm);
if (insn & (1 << 22)) {
if (insn & (1 << 7)) {
gen_revsh(s, tmp);
} else {
ARCH(6T2);
gen_helper_rbit(tcg_ctx, tmp, tmp);
}
} else {
if (insn & (1 << 7))
gen_rev16(s, tmp);
else
tcg_gen_bswap32_i32(tcg_ctx, tmp, tmp);
}
store_reg(s, rd, tmp);
} else {
/* Halfword pack, [US]SAT, [US]SAT16, SEL, REV et al */
/* Done by decodetree */
goto illegal_op;
}
break;
case 2: /* Multiplies (Type 3). */
switch ((insn >> 20) & 0x7) {
case 5:
@ -10350,7 +10534,7 @@ static bool thumb_insn_is_16bit(DisasContext *s, uint32_t pc, uint32_t insn)
static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
uint32_t imm, shift, offset;
uint32_t imm, offset;
uint32_t rd, rn, rm, rs;
TCGv_i32 tmp;
TCGv_i32 tmp2;
@ -10605,36 +10789,8 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
}
break;
case 5:
op = (insn >> 21) & 0xf;
if (op == 6) {
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
/* All in decodetree */
goto illegal_op;
}
/* Halfword pack. */
tmp = load_reg(s, rn);
tmp2 = load_reg(s, rm);
shift = ((insn >> 10) & 0x1c) | ((insn >> 6) & 0x3);
if (insn & (1 << 5)) {
/* pkhtb */
if (shift == 0) {
shift = 31;
}
tcg_gen_sari_i32(tcg_ctx, tmp2, tmp2, shift);
tcg_gen_deposit_i32(tcg_ctx, tmp, tmp, tmp2, 0, 16);
} else {
/* pkhbt */
tcg_gen_shli_i32(tcg_ctx, tmp2, tmp2, shift);
tcg_gen_deposit_i32(tcg_ctx, tmp, tmp2, tmp, 0, 16);
}
tcg_temp_free_i32(tcg_ctx, tmp2);
store_reg(s, rd, tmp);
} else {
/* Data processing register constant shift. */
/* All done in decodetree. Reach here for illegal ops. */
goto illegal_op;
}
break;
case 13: /* Misc data processing. */
op = ((insn >> 22) & 6) | ((insn >> 7) & 1);
if (op < 4 && (insn & 0xf000) != 0xf000)
@ -10642,114 +10798,10 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
switch (op) {
case 0: /* Register controlled shift, in decodetree */
goto illegal_op;
case 1: /* Sign/zero extend. */
op = (insn >> 20) & 7;
switch (op) {
case 0: /* SXTAH, SXTH */
case 1: /* UXTAH, UXTH */
case 4: /* SXTAB, SXTB */
case 5: /* UXTAB, UXTB */
break;
case 2: /* SXTAB16, SXTB16 */
case 3: /* UXTAB16, UXTB16 */
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
goto illegal_op;
}
break;
default:
goto illegal_op;
}
if (rn != 15) {
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
goto illegal_op;
}
}
tmp = load_reg(s, rm);
shift = (insn >> 4) & 3;
/* ??? In many cases it's not necessary to do a
rotate, a shift is sufficient. */
tcg_gen_rotri_i32(tcg_ctx, tmp, tmp, shift * 8);
op = (insn >> 20) & 7;
switch (op) {
case 0: gen_sxth(tmp); break;
case 1: gen_uxth(tmp); break;
case 2: gen_sxtb16(tmp); break;
case 3: gen_uxtb16(tmp); break;
case 4: gen_sxtb(tmp); break;
case 5: gen_uxtb(tmp); break;
default:
g_assert_not_reached();
}
if (rn != 15) {
tmp2 = load_reg(s, rn);
if ((op >> 1) == 1) {
gen_add16(s, tmp, tmp2);
} else {
tcg_gen_add_i32(tcg_ctx, tmp, tmp, tmp2);
tcg_temp_free_i32(tcg_ctx, tmp2);
}
}
store_reg(s, rd, tmp);
break;
case 1: /* Sign/zero extend, in decodetree */
case 2: /* SIMD add/subtract, in decodetree */
case 3: /* Other data processing, in decodetree */
goto illegal_op;
case 3: /* Other data processing. */
op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
if (op < 4) {
/* Saturating add/subtract. */
/* All done in decodetree. Reach here for illegal ops. */
goto illegal_op;
} else {
switch (op) {
case 0x0a: /* rbit */
case 0x08: /* rev */
case 0x09: /* rev16 */
case 0x0b: /* revsh */
break;
case 0x10: /* sel */
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
goto illegal_op;
}
break;
case 0x18: /* clz, in decodetree */
case 0x20: /* crc32/crc32c, in decodetree */
case 0x21:
case 0x22:
case 0x28:
case 0x29:
case 0x2a:
goto illegal_op;
default:
goto illegal_op;
}
tmp = load_reg(s, rn);
switch (op) {
case 0x0a: /* rbit */
gen_helper_rbit(tcg_ctx, tmp, tmp);
break;
case 0x08: /* rev */
tcg_gen_bswap32_i32(tcg_ctx, tmp, tmp);
break;
case 0x09: /* rev16 */
gen_rev16(s, tmp);
break;
case 0x0b: /* revsh */
gen_revsh(s, tmp);
break;
case 0x10: /* sel */
tmp2 = load_reg(s, rm);
tmp3 = tcg_temp_new_i32(tcg_ctx);
tcg_gen_ld_i32(tcg_ctx, tmp3, tcg_ctx->cpu_env, offsetof(CPUARMState, GE));
gen_helper_sel_flags(tcg_ctx, tmp, tmp3, tmp, tmp2);
tcg_temp_free_i32(tcg_ctx, tmp3);
tcg_temp_free_i32(tcg_ctx, tmp2);
break;
default:
g_assert_not_reached();
}
}
store_reg(s, rd, tmp);
break;
case 4: case 5: /* 32-bit multiply. Sum of absolute differences. */
switch ((insn >> 20) & 7) {
case 0: /* 32 x 32 -> 32 */
@ -11103,60 +11155,8 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
* - Data-processing (plain binary immediate)
*/
if (insn & (1 << 24)) {
if (insn & (1 << 20))
/* Bitfield/Saturate, in decodetree */
goto illegal_op;
/* Bitfield/Saturate. */
op = (insn >> 21) & 7;
imm = insn & 0x1f;
shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
if (rn == 15) {
tmp = tcg_temp_new_i32(tcg_ctx);
tcg_gen_movi_i32(tcg_ctx, tmp, 0);
} else {
tmp = load_reg(s, rn);
}
switch (op) {
case 2: /* Signed bitfield extract, in decodetree */
case 6: /* Unsigned bitfield extract, in decodetree */
case 3: /* Bitfield insert/clear, in decodetree */
case 7:
goto illegal_op;
default: /* Saturate. */
if (op & 1) {
tcg_gen_sari_i32(tcg_ctx, tmp, tmp, shift);
} else {
tcg_gen_shli_i32(tcg_ctx, tmp, tmp, shift);
}
tmp2 = tcg_const_i32(tcg_ctx, imm);
if (op & 4) {
/* Unsigned. */
if ((op & 1) && shift == 0) {
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
tcg_temp_free_i32(tcg_ctx, tmp);
tcg_temp_free_i32(tcg_ctx, tmp2);
goto illegal_op;
}
gen_helper_usat16(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
} else {
gen_helper_usat(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
}
} else {
/* Signed. */
if ((op & 1) && shift == 0) {
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
tcg_temp_free_i32(tcg_ctx, tmp);
tcg_temp_free_i32(tcg_ctx, tmp2);
goto illegal_op;
}
gen_helper_ssat16(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
} else {
gen_helper_ssat(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
}
}
tcg_temp_free_i32(tcg_ctx, tmp2);
break;
}
store_reg(s, rd, tmp);
} else {
imm = ((insn & 0x04000000) >> 15)
| ((insn & 0x7000) >> 4) | (insn & 0xff);
@ -11849,8 +11849,8 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn)
tmp = load_reg(s, rn);
switch (op1) {
case 0: tcg_gen_bswap32_i32(tcg_ctx, tmp, tmp); break;
case 1: gen_rev16(s, tmp); break;
case 3: gen_revsh(s, tmp); break;
case 1: gen_rev16(s, tmp, tmp); break;
case 3: gen_revsh(s, tmp, tmp); break;
default:
g_assert_not_reached();
}