From 452da404cdbeb4fbec75fe98352549980509c012 Mon Sep 17 00:00:00 2001 From: Dmitry Selyutin Date: Mon, 29 May 2023 01:04:56 +0300 Subject: [PATCH] ppc/svp64: validate and fix modes --- gas/config/tc-ppc-svp64.c | 184 +++++++++++++++++++++++++++++++++++++- 1 file changed, 182 insertions(+), 2 deletions(-) diff --git a/gas/config/tc-ppc-svp64.c b/gas/config/tc-ppc-svp64.c index cbaaaf5fbd9..91977b9d45a 100644 --- a/gas/config/tc-ppc-svp64.c +++ b/gas/config/tc-ppc-svp64.c @@ -47,6 +47,14 @@ struct svp64_ctx { unsigned int mr : 1; unsigned int RG : 1; unsigned int crm : 1; + unsigned int bc_all : 1; + unsigned int bc_lru : 1; + unsigned int bc_brc : 1; + unsigned int bc_svstep : 1; + unsigned int bc_vsb : 1; + unsigned int bc_vlset : 1; + unsigned int bc_vli : 1; + unsigned int bc_snz : 1; }; #define SVP64_RC1_ACTIVE (1U << 3U) @@ -609,7 +617,177 @@ svp64_decode (char *str, struct svp64_ctx *svp64) } static void -svp64_validate (struct svp64_ctx *svp64) +svp64_validate_and_fix_mode_bc (struct svp64_ctx *svp64) +{ + /* + * Create mode and (overridden) src/dst widths. + * TODO: sanity-check BC modes. + */ + svp64->sv_mode = ((svp64->bc_svstep << SVP64_MODE_MOD2_MSB) | + (svp64->bc_vlset << SVP64_MODE_MOD2_LSB) | + (svp64->bc_snz << SVP64_MODE_BC_SNZ)); + svp64->srcwid = ((svp64->bc_vsb << 1) | svp64->bc_lru); + svp64->destwid = ((svp64->bc_lru << 1) | svp64->bc_all); +} + +static void +svp64_validate_and_fix_mode_mr (struct svp64_ctx *svp64) +{ + svp64->mode |= (1U << SVP64_MODE_REDUCE); + svp64_raise_if (svp64->dz, + "dest-zero not allowed in mr mode"); + + if (svp64->RG) + svp64->mode |= (1U << SVP64_MODE_RG); + + if (svp64->crm) + { + svp64->mode |= (1U << SVP64_MODE_CRM); + svp64_raise_if (!svp64->desc->Rc, "CRM only allowed when Rc=1"); + } + + /* + * Bit of weird encoding to jam zero-pred or SVM mode in. + * SVM mode can be enabled only when SUBVL=2/3/4 (vec2/3/4) + */ + if (svp64->subvl == 0) + svp64->mode |= (svp64->dz << SVP64_MODE_DZ); +} + +static void +svp64_validate_and_fix_mode_ff(struct svp64_ctx *svp64) +{ + svp64_raise_if (svp64->sz, + "dest-zero not allowed in ff mode"); + + if (svp64->ff & SVP64_RC1_ACTIVE) + { + svp64->mode |= (1U << SVP64_MODE_RC1); + svp64->mode |= (svp64->dz << SVP64_MODE_DZ); + svp64_raise_if (svp64->desc->Rc, + "ffirst RC1/~RC1 only possible when Rc=0"); + if (svp64->ff & SVP64_RC1_INVERT) + svp64->mode |= (1U << SVP64_MODE_INV); + } + else + { + svp64_raise_if (svp64->dz, + "dst-zero not allowed in ffirst BO"); + svp64_raise_if (!svp64->desc->Rc, + "ffirst BO only possible when Rc=1"); + svp64->mode |= (svp64->ff << SVP64_MODE_BO_LSB); + } +} + +static void +svp64_validate_and_fix_mode_sat(struct svp64_ctx *svp64) +{ + svp64->mode |= (svp64->sz << SVP64_MODE_SZ); + svp64->mode |= (svp64->dz << SVP64_MODE_DZ); + svp64->mode |= (svp64->sat << SVP64_MODE_N); +} + +static void +svp64_validate_and_fix_mode_strided(struct svp64_ctx *svp64) +{ + svp64->mode |= (svp64->dz << SVP64_MODE_DZ); + svp64->mode |= (svp64->sz << SVP64_MODE_SZ); + svp64->mode |= (svp64->sea << SVP64_MODE_SEA); +} + +static void +svp64_validate_and_fix_mode_explicit(struct svp64_ctx *svp64) +{ + static void (*const table[])(struct svp64_ctx *svp64) = { + svp64_validate_and_fix_mode_mr, + svp64_validate_and_fix_mode_ff, + svp64_validate_and_fix_mode_sat, + }; + + if ((svp64->sv_mode == 0b01) && (svp64->desc->mode == SVP64_MODE_LDST_IDX)) + return svp64_validate_and_fix_mode_strided (svp64); + + return (*table[svp64->sv_mode]) (svp64); +} + +static void +svp64_validate_and_fix_mode_normal (struct svp64_ctx *svp64) +{ + svp64->mode |= (svp64->sz << SVP64_MODE_SZ); + svp64->mode |= (svp64->dz << SVP64_MODE_DZ); + if ((svp64->desc->mode == SVP64_MODE_LDST_IMM) || + (svp64->desc->mode == SVP64_MODE_LDST_IDX)) + { + /* TODO: for now, LD/ST-indexed is ignored. */ + svp64->mode |= (svp64->els << SVP64_MODE_ELS_NORMAL); + } + else + { + /* + * TODO: reduce and subvector mode. + * 00 1 dz CRM reduce mode (mr), SUBVL=1 + * 00 1 SVM CRM subvector reduce mode, SUBVL>1 + */ + } + svp64->sv_mode = 0; +} + +/* + * There are 4 different modes, here, which will be partly-merged-in: + * is_ldst is merged in with "normal", but is_bc is so different it's + * done separately. Likewise is_cr (when it is done). + * + * "normal" arithmetic: https://libre-soc.org/openpower/sv/normal + * | 0-1 | 2 | 3 4 | description | + * | --- | --- |---------|------------------------------------------ | + * | 00 | 0 | dz sz | normal mode | + * | 00 | 1 | 0 RG | scalar reduce mode (mr), SUBVL=1 | + * | 00 | 1 | 1 / | parallel reduce mode (mr), SUBVL=1 | + * | 00 | 1 | SVM RG | subvector reduce mode, SUBVL>1 | + * | 01 | inv | CR-bit | Rc=1: ffirst CR sel | + * | 01 | inv | VLi RC1 | Rc=0: ffirst z/nonz | + * | 10 | N | dz sz | sat mode: N=0/1 u/s | + * | 11 | inv | CR-bit | Rc=1: pred-result CR sel | + * | 11 | inv | dz RC1 | Rc=0: pred-result z/nonz | + * + * LD/ST-immediate: https://libre-soc.org/openpower/sv/ldst + * | 0-1 | 2 | 3 4 | description | + * | --- | --- |---------|------------------------------------------ | + * | 00 | 0 | dz els | normal mode | + * | 00 | 1 | dz shf | shift mode | + * | 01 | inv | CR-bit | Rc=1: ffirst CR sel | + * | 01 | inv | els RC1 | Rc=0: ffirst z/nonz | + * | 10 | N | dz els | sat mode: N=0/1 u/s | + * | 11 | inv | CR-bit | Rc=1: pred-result CR sel | + * | 11 | inv | els RC1 | Rc=0: pred-result z/nonz | + * + * LD/ST-indexed (RA+RB): https://libre-soc.org/openpower/sv/ldst + * | 0-1 | 2 | 3 4 | description | + * | --- | --- |---------|------------------------------------------ | + * | 00 | SEA | dz sz | normal mode | + * | 01 | SEA | dz sz | Strided (scalar only source) | + * | 10 | N | dz sz | sat mode: N=0/1 u/s | + * | 11 | inv | CR-bit | Rc=1: pred-result CR sel | + * | 11 | inv | dz RC1 | Rc=0: pred-result z/nonz | + * + * ...and branches/cr_ops are still in development. + */ +static void +svp64_validate_and_fix_mode (struct svp64_ctx *svp64) +{ + if (svp64->desc->mode == SVP64_MODE_BRANCH) + svp64_validate_and_fix_mode_bc (svp64); + else if (svp64->sv_mode_explicit) + svp64_validate_and_fix_mode_explicit (svp64); + else + svp64_validate_and_fix_mode_normal (svp64); + + svp64->mode |= (((svp64->sv_mode >> 0) & 0x1) << SVP64_MODE_MOD2_LSB); + svp64->mode |= (((svp64->sv_mode >> 1) & 0x1) << SVP64_MODE_MOD2_MSB); +} + +static void +svp64_validate_and_fix (struct svp64_ctx *svp64) { if (svp64->desc->ptype == SVP64_PTYPE_P2) { @@ -667,6 +845,8 @@ svp64_validate (struct svp64_ctx *svp64) svp64_raise_if (!svp64->has_smask && !svp64->mask_m_specified, "src zeroing requires a source predicate"); } + + svp64_validate_and_fix_mode (svp64); } static void @@ -680,7 +860,7 @@ svp64_assemble (char *str) memset (&svp64, 0, sizeof (svp64)); svp64_decode (str, &svp64); - svp64_validate (&svp64); + svp64_validate_and_fix (&svp64); as_warn (_("opcode ignored (desc=%p)"), svp64.desc); memcpy (str, "nop", sizeof ("nop")); -- 2.30.2