target/arm: Convert Bitfield to decodetree

Convert the BFM, SBFM, UBFM instructions.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20230512144106.3608981-12-peter.maydell@linaro.org
[PMM: Rebased]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Richard Henderson 2023-05-12 15:40:57 +01:00 committed by Peter Maydell
parent ee0daeb946
commit 5e451ae63b
2 changed files with 94 additions and 63 deletions

View File

@ -84,3 +84,16 @@ MOVZ . 10 100101 .. ................ ..... @movw_64
MOVZ . 10 100101 .. ................ ..... @movw_32
MOVK . 11 100101 .. ................ ..... @movw_64
MOVK . 11 100101 .. ................ ..... @movw_32
# Bitfield
&bitfield rd rn sf immr imms
@bitfield_64 1 .. ...... 1 immr:6 imms:6 rn:5 rd:5 &bitfield sf=1
@bitfield_32 0 .. ...... 0 0 immr:5 0 imms:5 rn:5 rd:5 &bitfield sf=0
SBFM . 00 100110 . ...... ...... ..... ..... @bitfield_64
SBFM . 00 100110 . ...... ...... ..... ..... @bitfield_32
BFM . 01 100110 . ...... ...... ..... ..... @bitfield_64
BFM . 01 100110 . ...... ...... ..... ..... @bitfield_32
UBFM . 10 100110 . ...... ...... ..... ..... @bitfield_64
UBFM . 10 100110 . ...... ...... ..... ..... @bitfield_32

View File

@ -4431,82 +4431,103 @@ static bool trans_MOVK(DisasContext *s, arg_movw *a)
return true;
}
/* Bitfield
* 31 30 29 28 23 22 21 16 15 10 9 5 4 0
* +----+-----+-------------+---+------+------+------+------+
* | sf | opc | 1 0 0 1 1 0 | N | immr | imms | Rn | Rd |
* +----+-----+-------------+---+------+------+------+------+
/*
* Bitfield
*/
static void disas_bitfield(DisasContext *s, uint32_t insn)
static bool trans_SBFM(DisasContext *s, arg_SBFM *a)
{
unsigned int sf, n, opc, ri, si, rn, rd, bitsize, pos, len;
TCGv_i64 tcg_rd, tcg_tmp;
TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
TCGv_i64 tcg_tmp = read_cpu_reg(s, a->rn, 1);
unsigned int bitsize = a->sf ? 64 : 32;
unsigned int ri = a->immr;
unsigned int si = a->imms;
unsigned int pos, len;
sf = extract32(insn, 31, 1);
opc = extract32(insn, 29, 2);
n = extract32(insn, 22, 1);
ri = extract32(insn, 16, 6);
si = extract32(insn, 10, 6);
rn = extract32(insn, 5, 5);
rd = extract32(insn, 0, 5);
bitsize = sf ? 64 : 32;
if (sf != n || ri >= bitsize || si >= bitsize || opc > 2) {
unallocated_encoding(s);
return;
}
tcg_rd = cpu_reg(s, rd);
/* Suppress the zero-extend for !sf. Since RI and SI are constrained
to be smaller than bitsize, we'll never reference data outside the
low 32-bits anyway. */
tcg_tmp = read_cpu_reg(s, rn, 1);
/* Recognize simple(r) extractions. */
if (si >= ri) {
/* Wd<s-r:0> = Wn<s:r> */
len = (si - ri) + 1;
if (opc == 0) { /* SBFM: ASR, SBFX, SXTB, SXTH, SXTW */
tcg_gen_sextract_i64(tcg_rd, tcg_tmp, ri, len);
goto done;
} else if (opc == 2) { /* UBFM: UBFX, LSR, UXTB, UXTH */
tcg_gen_extract_i64(tcg_rd, tcg_tmp, ri, len);
return;
if (!a->sf) {
tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
}
/* opc == 1, BFXIL fall through to deposit */
tcg_gen_shri_i64(tcg_tmp, tcg_tmp, ri);
pos = 0;
} else {
/* Handle the ri > si case with a deposit
* Wd<32+s-r,32-r> = Wn<s:0>
*/
/* Wd<32+s-r,32-r> = Wn<s:0> */
len = si + 1;
pos = (bitsize - ri) & (bitsize - 1);
}
if (opc == 0 && len < ri) {
/* SBFM: sign extend the destination field from len to fill
the balance of the word. Let the deposit below insert all
of those sign bits. */
if (len < ri) {
/*
* Sign extend the destination field from len to fill the
* balance of the word. Let the deposit below insert all
* of those sign bits.
*/
tcg_gen_sextract_i64(tcg_tmp, tcg_tmp, 0, len);
len = ri;
}
if (opc == 1) { /* BFM, BFXIL */
tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, pos, len);
} else {
/* SBFM or UBFM: We start with zero, and we haven't modified
any bits outside bitsize, therefore the zero-extension
below is unneeded. */
/*
* We start with zero, and we haven't modified any bits outside
* bitsize, therefore no final zero-extension is unneeded for !sf.
*/
tcg_gen_deposit_z_i64(tcg_rd, tcg_tmp, pos, len);
return;
}
return true;
}
static bool trans_UBFM(DisasContext *s, arg_UBFM *a)
{
TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
TCGv_i64 tcg_tmp = read_cpu_reg(s, a->rn, 1);
unsigned int bitsize = a->sf ? 64 : 32;
unsigned int ri = a->immr;
unsigned int si = a->imms;
unsigned int pos, len;
tcg_rd = cpu_reg(s, a->rd);
tcg_tmp = read_cpu_reg(s, a->rn, 1);
if (si >= ri) {
/* Wd<s-r:0> = Wn<s:r> */
len = (si - ri) + 1;
tcg_gen_extract_i64(tcg_rd, tcg_tmp, ri, len);
} else {
/* Wd<32+s-r,32-r> = Wn<s:0> */
len = si + 1;
pos = (bitsize - ri) & (bitsize - 1);
tcg_gen_deposit_z_i64(tcg_rd, tcg_tmp, pos, len);
}
return true;
}
static bool trans_BFM(DisasContext *s, arg_BFM *a)
{
TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
TCGv_i64 tcg_tmp = read_cpu_reg(s, a->rn, 1);
unsigned int bitsize = a->sf ? 64 : 32;
unsigned int ri = a->immr;
unsigned int si = a->imms;
unsigned int pos, len;
tcg_rd = cpu_reg(s, a->rd);
tcg_tmp = read_cpu_reg(s, a->rn, 1);
if (si >= ri) {
/* Wd<s-r:0> = Wn<s:r> */
tcg_gen_shri_i64(tcg_tmp, tcg_tmp, ri);
len = (si - ri) + 1;
pos = 0;
} else {
/* Wd<32+s-r,32-r> = Wn<s:0> */
len = si + 1;
pos = (bitsize - ri) & (bitsize - 1);
}
done:
if (!sf) { /* zero extend final result */
tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, pos, len);
if (!a->sf) {
tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
}
return true;
}
/* Extract
@ -4573,9 +4594,6 @@ static void disas_extract(DisasContext *s, uint32_t insn)
static void disas_data_proc_imm(DisasContext *s, uint32_t insn)
{
switch (extract32(insn, 23, 6)) {
case 0x26: /* Bitfield */
disas_bitfield(s, insn);
break;
case 0x27: /* Extract */
disas_extract(s, insn);
break;