target/arm: Make asimd_imm_const() public

The function asimd_imm_const() in translate-neon.c is an
implementation of the pseudocode AdvSIMDExpandImm(), which we will
also want for MVE.  Move the implementation to translate.c, with a
prototype in translate.h.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20210628135835.6690-4-peter.maydell@linaro.org
This commit is contained in:
Peter Maydell 2021-06-28 14:58:20 +01:00
parent 303db86fc7
commit dfd66bc0f3
3 changed files with 73 additions and 63 deletions

View File

@ -1781,69 +1781,6 @@ DO_FP_2SH(VCVT_UH, gen_helper_gvec_vcvt_uh)
DO_FP_2SH(VCVT_HS, gen_helper_gvec_vcvt_hs)
DO_FP_2SH(VCVT_HU, gen_helper_gvec_vcvt_hu)
static uint64_t asimd_imm_const(uint32_t imm, int cmode, int op)
{
/*
* Expand the encoded constant.
* Note that cmode = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE.
* We choose to not special-case this and will behave as if a
* valid constant encoding of 0 had been given.
* cmode = 15 op = 1 must UNDEF; we assume decode has handled that.
*/
switch (cmode) {
case 0: case 1:
/* no-op */
break;
case 2: case 3:
imm <<= 8;
break;
case 4: case 5:
imm <<= 16;
break;
case 6: case 7:
imm <<= 24;
break;
case 8: case 9:
imm |= imm << 16;
break;
case 10: case 11:
imm = (imm << 8) | (imm << 24);
break;
case 12:
imm = (imm << 8) | 0xff;
break;
case 13:
imm = (imm << 16) | 0xffff;
break;
case 14:
if (op) {
/*
* This is the only case where the top and bottom 32 bits
* of the encoded constant differ.
*/
uint64_t imm64 = 0;
int n;
for (n = 0; n < 8; n++) {
if (imm & (1 << n)) {
imm64 |= (0xffULL << (n * 8));
}
}
return imm64;
}
imm |= (imm << 8) | (imm << 16) | (imm << 24);
break;
case 15:
imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
| ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
break;
}
if (op) {
imm = ~imm;
}
return dup_const(MO_32, imm);
}
static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a,
GVecGen2iFn *fn)
{

View File

@ -90,6 +90,63 @@ void arm_translate_init(void)
a64_translate_init();
}
uint64_t asimd_imm_const(uint32_t imm, int cmode, int op)
{
/* Expand the encoded constant as per AdvSIMDExpandImm pseudocode */
switch (cmode) {
case 0: case 1:
/* no-op */
break;
case 2: case 3:
imm <<= 8;
break;
case 4: case 5:
imm <<= 16;
break;
case 6: case 7:
imm <<= 24;
break;
case 8: case 9:
imm |= imm << 16;
break;
case 10: case 11:
imm = (imm << 8) | (imm << 24);
break;
case 12:
imm = (imm << 8) | 0xff;
break;
case 13:
imm = (imm << 16) | 0xffff;
break;
case 14:
if (op) {
/*
* This is the only case where the top and bottom 32 bits
* of the encoded constant differ.
*/
uint64_t imm64 = 0;
int n;
for (n = 0; n < 8; n++) {
if (imm & (1 << n)) {
imm64 |= (0xffULL << (n * 8));
}
}
return imm64;
}
imm |= (imm << 8) | (imm << 16) | (imm << 24);
break;
case 15:
imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
| ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
break;
}
if (op) {
imm = ~imm;
}
return dup_const(MO_32, imm);
}
/* Generate a label used for skipping this instruction */
void arm_gen_condlabel(DisasContext *s)
{

View File

@ -532,4 +532,20 @@ static inline MemOp finalize_memop(DisasContext *s, MemOp opc)
return opc | s->be_data;
}
/**
* asimd_imm_const: Expand an encoded SIMD constant value
*
* Expand a SIMD constant value. This is essentially the pseudocode
* AdvSIMDExpandImm, except that we also perform the boolean NOT needed for
* VMVN and VBIC (when cmode < 14 && op == 1).
*
* The combination cmode == 15 op == 1 is a reserved encoding for AArch32;
* callers must catch this.
*
* cmode = 2,3,4,5,6,7,10,11,12,13 imm=0 was UNPREDICTABLE in v7A but
* is either not unpredictable or merely CONSTRAINED UNPREDICTABLE in v8A;
* we produce an immediate constant value of 0 in these cases.
*/
uint64_t asimd_imm_const(uint32_t imm, int cmode, int op);
#endif /* TARGET_ARM_TRANSLATE_H */