From 5c4bcb163395a27e86bdc88730b83004ac3766f0 Mon Sep 17 00:00:00 2001 From: Dmitry Selyutin Date: Mon, 29 May 2023 01:04:56 +0300 Subject: [PATCH] ppc/svp64: remap operands and build instructions --- gas/config/tc-ppc-svp64.c | 181 ++++++++++++++++++++++++++++++++++++++ gas/config/tc-ppc.c | 16 +++- 2 files changed, 196 insertions(+), 1 deletion(-) diff --git a/gas/config/tc-ppc-svp64.c b/gas/config/tc-ppc-svp64.c index b6dd549e7f1..f840da7b2fc 100644 --- a/gas/config/tc-ppc-svp64.c +++ b/gas/config/tc-ppc-svp64.c @@ -24,6 +24,7 @@ struct svp64_ctx { const char *name; const struct svp64_desc *desc; + struct svp64_insn insn; unsigned int sv_mode_explicit : 1; unsigned int sv_mode : 2; unsigned int mode : 5; @@ -912,6 +913,174 @@ svp64_validate_and_fix (struct svp64_ctx *svp64) svp64_validate_and_fix_mode (svp64); } +static void +svp64_remap_extra (struct svp64_ctx *svp64, + ppc_opindex_t opindex, uint32_t value) +{ + const struct svp64_extra_desc *desc; + + desc = svp64_extra_desc (svp64->desc, opindex); + svp64_raise_if ((desc == NULL), "cannot remap EXTRA"); + + return (*desc->set) (&svp64->insn, value); +} + +static int64_t +svp64_remap_reg (struct svp64_ctx *svp64, int64_t value, + ppc_opindex_t opindex, bool vector) +{ + uint32_t field; + uint32_t sv_extra; + + svp64_raise_if (((value < 0) || (value > 127)), + "register does not fit the expected range 0..127"); + field = (uint32_t)value; + + if (vector) + { + /* cut into 5-bits 2-bits FFFFF SS */ + sv_extra = (field & 0x3); + field >>= 2; + } + else + { + /* cut into 2-bits 5-bits SS FFFFF */ + sv_extra = (field >> 5); + field &= 0x1F; + } + + if (svp64->desc->etype == SVP64_ETYPE_EXTRA2) + { + if (vector) + { + /* range is r0-r127 in increments of 2 (r0 r2 ... r126) */ + svp64_raise_if ( ((sv_extra & 1) != 0), + "vector register cannot fit into EXTRA2"); + sv_extra = (0x2 | (sv_extra >> 1)); + } + else + { + /* range is r0-r63 in increments of 1 */ + svp64_raise_if ( ((sv_extra >> 1) != 0), + "scalar register cannot fit into EXTRA2"); + sv_extra &= 0x1; + } + } + else if (vector) + { + /* EXTRA3 vector bit needs marking */ + sv_extra |= 0x4; + } + + svp64_remap_extra (svp64, opindex, sv_extra); + + return field; +} + +static int64_t +svp64_remap_gpr (struct svp64_ctx *svp64, int64_t value, + ppc_opindex_t opindex, bool vector) +{ + return svp64_remap_reg (svp64, value, opindex, vector); +} + +static int64_t +svp64_remap_fpr (struct svp64_ctx *svp64, int64_t value, + ppc_opindex_t opindex, bool vector) +{ + return svp64_remap_reg (svp64, value, opindex, vector); +} + +static int64_t +svp64_remap_cr (struct svp64_ctx *svp64, int64_t value, + ppc_opindex_t opindex, bool vector, bool cr_bit) +{ + uint32_t field; + uint32_t subfield; + uint32_t sv_extra; + + svp64_raise_if (((value < 0) || (value > 127)), + "register does not fit the expected range 0..127"); + field = (uint32_t)value; + + if (cr_bit) + { + subfield = (field & 0x3); + field >>= 2; + } + + if (vector) + { + /* cut into 3-bits 4-bits FFF SSSS but will cut 2 zeros off later */ + sv_extra = (field & 0xf); + field >>= 4; + } + else + { + /* cut into 2-bits 3-bits SS FFF */ + sv_extra = (field >> 3); + field &= 0x7; + } + + if (svp64->desc->etype == SVP64_ETYPE_EXTRA2) + { + if (vector) + { + svp64_raise_if (((sv_extra & 0x7) != 0), + "vector CR cannot fit into EXTRA2"); + sv_extra = (0x2 | (sv_extra >> 3)); + } + else + { + svp64_raise_if (((sv_extra >> 1) != 0), + "scalar CR cannot fit into EXTRA2"); + sv_extra &= 0x1; + } + } + else + { + if (vector) + { + svp64_raise_if (((sv_extra & 0x3) != 0), + "vector CR cannot fit into EXTRA3"); + sv_extra = (0x4 | (sv_extra >> 2)); + } + else + { + svp64_raise_if (((sv_extra >> 2) != 0), + "scalar CR cannot fit into EXTRA3"); + sv_extra &= 0x3; + } + } + + if (cr_bit) + field = ((field << 2) | subfield); + + svp64_remap_extra (svp64, opindex, sv_extra); + + return field; +} + +static int64_t +svp64_remap (struct svp64_ctx *ctx, int64_t value, + const struct powerpc_operand *operand, bool vector) +{ + const ppc_opindex_t opindex = (ppc_opindex_t)(operand - powerpc_operands); + + if ((operand->flags & (PPC_OPERAND_GPR | PPC_OPERAND_GPR_0)) != 0) + return svp64_remap_gpr (ctx, value, opindex, vector); + else if ((operand->flags & PPC_OPERAND_FPR) != 0) + return svp64_remap_fpr (ctx, value, opindex, vector); + else if ((operand->flags & (PPC_OPERAND_CR_BIT | PPC_OPERAND_CR_REG)) != 0) + { + bool cr_bit = ((operand->flags & PPC_OPERAND_CR_BIT) != 0); + + return svp64_remap_cr (ctx, value, opindex, vector, cr_bit); + } + + return value; +} + static void svp64_assemble (char *str) { @@ -925,5 +1094,17 @@ svp64_assemble (char *str) svp64_decode (str, &svp64); svp64_validate_and_fix (&svp64); + svp64_insn_set_prefix_PO (&svp64.insn, 0x1); + svp64_insn_set_prefix_id (&svp64.insn, 0x3); + + svp64_insn_set_prefix_rm_mode (&svp64.insn, svp64.mode); + if (svp64.desc->ptype == SVP64_PTYPE_P2) + svp64_insn_set_prefix_rm_smask (&svp64.insn, svp64.smask); + svp64_insn_set_prefix_rm_mmode (&svp64.insn, svp64.mmode); + svp64_insn_set_prefix_rm_mask (&svp64.insn, svp64.pmask); + svp64_insn_set_prefix_rm_subvl (&svp64.insn, svp64.subvl); + svp64_insn_set_prefix_rm_ewsrc (&svp64.insn, svp64.srcwid); + svp64_insn_set_prefix_rm_elwidth (&svp64.insn, svp64.destwid); + ppc_assemble (str, &svp64); } diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index f6320dcca21..1900029f5e6 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -3574,6 +3574,8 @@ ppc_assemble (char *str, struct svp64_ctx *svp64) as_bad (_("missing operand")); else if (ex.X_op == O_register) { + int64_t val = ex.X_add_number; + if ((ex.X_md & ~operand->flags & (PPC_OPERAND_GPR | PPC_OPERAND_FPR | PPC_OPERAND_VR @@ -3584,7 +3586,10 @@ ppc_assemble (char *str, struct svp64_ctx *svp64) && ex.X_add_number != 0 && (operand->flags & PPC_OPERAND_GPR_0) != 0))) as_warn (_("invalid register expression")); - insn = ppc_insert_operand (insn, operand, ex.X_add_number, + + if (svp64) + val = svp64_remap (svp64, val, operand, vector); + insn = ppc_insert_operand (insn, operand, val, ppc_cpu, (char *) NULL, 0); } else if (ex.X_op == O_constant @@ -3690,6 +3695,8 @@ ppc_assemble (char *str, struct svp64_ctx *svp64) break; } #endif /* OBJ_ELF */ + if (svp64) + val = svp64_remap (svp64, val, operand, vector); insn = ppc_insert_operand (insn, operand, val, ppc_cpu, NULL, 0); } else @@ -4154,6 +4161,13 @@ ppc_assemble (char *str, struct svp64_ctx *svp64) if ((frag_now_fix () & addr_mask) != 0) as_bad (_("instruction address is not a multiple of %d"), addr_mask + 1); + /* Take care of SVP64 instructions. */ + if (svp64) + { + svp64_insn_set_suffix (&svp64->insn, insn); + insn = svp64_insn_get (&svp64->insn); + } + /* Differentiate between two, four, and eight byte insns. */ insn_length = 4; if ((ppc_cpu & PPC_OPCODE_VLE) != 0 && PPC_OP_SE_VLE (insn)) -- 2.30.2