From 5a348acc6102a7935278cb2a715bffc618960dd8 Mon Sep 17 00:00:00 2001 From: Dmitry Selyutin Date: Sun, 24 Jul 2022 16:18:29 +0300 Subject: [PATCH] ppc/svp64: support SVP64 vectors --- gas/config/tc-ppc-svp64.c | 50 ++++++++++++++++ gas/config/tc-ppc.c | 123 ++++++++++++++++++++++++++++++-------- gas/config/tc-ppc.h | 16 ++++- 3 files changed, 161 insertions(+), 28 deletions(-) diff --git a/gas/config/tc-ppc-svp64.c b/gas/config/tc-ppc-svp64.c index a87e71c2038..158f1efa01d 100644 --- a/gas/config/tc-ppc-svp64.c +++ b/gas/config/tc-ppc-svp64.c @@ -70,6 +70,56 @@ enum svp64_type { SVP64_TYPE_BC, }; +static void +svp64_operand (expressionS *exp) +{ + bool vector = false; + bool compat = false; + char *origin = input_line_pointer; + + if (input_line_pointer[0] == '*') + { + vector = true; + if (ISDIGIT (input_line_pointer[1])) + { + input_line_pointer[0] = 'r'; + compat = true; + } + else + ++input_line_pointer; + } + + if (!vector && !compat && !reg_names_p && + (input_line_pointer[0] != '%' || !ISALPHA (input_line_pointer[1]))) + return; + + if (!compat && (*input_line_pointer == '%')) + ++input_line_pointer; + + ppc_operand_common (exp, svp64_regs, svp64_num_regs); + + if (exp->X_op == O_absent) + input_line_pointer = origin; + else if (vector && + ((exp->X_op == O_register) || (exp->X_op == O_constant))) + exp->X_op = O_vector; + + if (compat) + *origin = '*'; +} + +static void +svp64_parse_name (const char *name, expressionS *exp, enum expr_mode mode) +{ + ppc_parse_name_common (name, exp, mode, svp64_regs, svp64_num_regs); +} + +static bool +svp64_special_expr (expressionS *exp) +{ + return (exp->X_op == O_vector); +} + static jmp_buf svp64_exception; #define svp64_raise(...) \ diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index 25e4a7de2f8..9f688b6e9a5 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -39,7 +39,18 @@ struct svp64_ctx; static void -ppc_assemble (char *str, struct svp64_ctx *svp64 ATTRIBUTE_UNUSED); +ppc_assemble (char *str, struct svp64_ctx *svp64); + +static bool reg_names_p; + +static void +ppc_operand_common (expressionS *expressionP, + const struct powerpc_pd_reg *regs, size_t num); + +static void +ppc_parse_name_common (const char *name, + expressionS *exp, enum expr_mode mode, + const struct powerpc_pd_reg *regs, size_t num); #include "tc-ppc-svp64.c" @@ -814,13 +825,30 @@ reg_name_search (const struct powerpc_pd_reg *regs, int regcount, const char *na /* Called for a non-symbol, non-number operand. Handles %reg. */ -void -md_operand (expressionS *expressionP) +static void +ppc_operand_common (expressionS *expressionP, + const struct powerpc_pd_reg *regs, size_t num) { - const struct powerpc_pd_reg *reg; + char endc; char *name; + const struct powerpc_pd_reg *reg; + + endc = get_symbol_name (&name); + reg = reg_name_search (regs, num, name); + restore_line_pointer (endc); + + if (reg != NULL) + { + expressionP->X_op = O_register; + expressionP->X_add_number = reg->value; + expressionP->X_md = reg->flags; + } +} + +static void +ppc_operand_default (expressionS *exp) +{ char *start; - char c; if (input_line_pointer[0] != '%' || !ISALPHA (input_line_pointer[1])) return; @@ -828,21 +856,17 @@ md_operand (expressionS *expressionP) start = input_line_pointer; ++input_line_pointer; - c = get_symbol_name (&name); - reg = reg_name_search (pre_defined_registers, - ARRAY_SIZE (pre_defined_registers), name); - *input_line_pointer = c; + ppc_operand_common (exp, + pre_defined_registers, + ARRAY_SIZE (pre_defined_registers)); - if (reg != NULL) - { - expressionP->X_op = O_register; - expressionP->X_add_number = reg->value; - expressionP->X_md = reg->flags; - } - else + if (exp->X_op == O_absent) input_line_pointer = start; } +void +(*ppc_operand) (expressionS *expressionP) = ppc_operand_default; + /* Whether to do the special parsing. */ static bool cr_operand; @@ -861,16 +885,17 @@ static const struct powerpc_pd_reg cr_cond[] = to use for condition codes, and recognises other registers when -mregnames. */ -void -ppc_parse_name (const char *name, expressionS *exp, enum expr_mode mode) +static void +ppc_parse_name_common (const char *name, + expressionS *exp, enum expr_mode mode, + const struct powerpc_pd_reg *regs, size_t num) { const struct powerpc_pd_reg *reg = NULL; if (cr_operand) reg = reg_name_search (cr_cond, ARRAY_SIZE (cr_cond), name); if (reg == NULL && (cr_operand || reg_names_p)) - reg = reg_name_search (pre_defined_registers, - ARRAY_SIZE (pre_defined_registers), name); + reg = reg_name_search (regs, num, name); if (reg != NULL) { exp->X_op = O_register; @@ -894,11 +919,15 @@ ppc_parse_name (const char *name, expressionS *exp, enum expr_mode mode) if (mode != expr_defer && !S_FORCE_RELOC (sym, 0)) { - segT segment = S_GET_SEGMENT (sym); - if (segment == absolute_section || segment == reg_section) + segT sym_seg = S_GET_SEGMENT (sym); + expressionS *sym_exp = symbol_get_value_expression (sym); + + if ((sym_seg == absolute_section) + || (sym_seg == reg_section) + || (((ppc_cpu & PPC_OPCODE_SVP64) != 0) && svp64_special_expr (sym_exp))) { resolve_symbol_value (sym); - *exp = *symbol_get_value_expression (sym); + *exp = *sym_exp; done = true; } } @@ -910,6 +939,32 @@ ppc_parse_name (const char *name, expressionS *exp, enum expr_mode mode) } } +static void +ppc_parse_name_default (const char *name, expressionS *exp, enum expr_mode mode) +{ + ppc_parse_name_common (name, exp, mode, + pre_defined_registers, ARRAY_SIZE (pre_defined_registers)); +} + +void +(*ppc_parse_name) (const char *name, expressionS *exp, enum expr_mode mode) = ppc_parse_name_default; + +bool +ppc_resolve_symbol (symbolS *sym ATTRIBUTE_UNUSED, + valueT *val ATTRIBUTE_UNUSED, segT *seg) +{ + switch (symbol_get_value_expression (sym)->X_op) + { + case O_vector: + *seg = reg_section; + break; + default: + abort (); + } + + return true; +} + /* Propagate X_md and check register expressions. This is to support condition codes like 4*cr5+eq. */ @@ -1870,6 +1925,11 @@ md_begin (void) ppc_cie_data_alignment = ppc_obj64 ? -8 : -4; ppc_dwarf2_line_min_insn_length = (ppc_cpu & PPC_OPCODE_VLE) ? 2 : 4; + if (ppc_cpu & PPC_OPCODE_SVP64) + { + ppc_parse_name = svp64_parse_name; + ppc_operand = svp64_operand; + } #ifdef OBJ_ELF /* Set the ELF flags if desired. */ @@ -3298,7 +3358,7 @@ is_svp64_insn (char *str) /* This routine is called for each instruction to be assembled. */ static void -ppc_assemble (char *str, struct svp64_ctx *svp64 ATTRIBUTE_UNUSED) +ppc_assemble (char *str, struct svp64_ctx *svp64) { char *s; const struct powerpc_opcode *opcode; @@ -3385,6 +3445,7 @@ ppc_assemble (char *str, struct svp64_ctx *svp64 ATTRIBUTE_UNUSED) fc = 0; for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++) { + bool vector; const struct powerpc_operand *operand; const char *errmsg; char *hold; @@ -3468,11 +3529,21 @@ ppc_assemble (char *str, struct svp64_ctx *svp64 ATTRIBUTE_UNUSED) input_line_pointer = str; cr_operand = ((operand->flags & PPC_OPERAND_CR_BIT) != 0 || (operand->flags & PPC_OPERAND_CR_REG) != 0); + memset (&ex, 0, sizeof (ex)); expression (&ex); cr_operand = false; str = input_line_pointer; input_line_pointer = hold; + vector = false; + if (ex.X_op == O_vector) + { + if (!svp64) + as_bad (_("vector operand not supported")); + ex.X_op = O_register; + vector = true; + } + if (ex.X_op == O_illegal) as_bad (_("illegal operand")); else if (ex.X_op == O_absent) @@ -3484,9 +3555,9 @@ ppc_assemble (char *str, struct svp64_ctx *svp64 ATTRIBUTE_UNUSED) & (PPC_OPERAND_GPR | PPC_OPERAND_FPR | PPC_OPERAND_VR | PPC_OPERAND_VSR | PPC_OPERAND_CR_BIT | PPC_OPERAND_CR_REG | PPC_OPERAND_SPR | PPC_OPERAND_GQR | PPC_OPERAND_ACC)) != 0 - && !((ex.X_md & PPC_OPERAND_GPR) != 0 + && !(vector || ((ex.X_md & PPC_OPERAND_GPR) != 0 && ex.X_add_number != 0 - && (operand->flags & PPC_OPERAND_GPR_0) != 0)) + && (operand->flags & PPC_OPERAND_GPR_0) != 0))) as_warn (_("invalid register expression")); insn = ppc_insert_operand (insn, operand, ex.X_add_number, ppc_cpu, (char *) NULL, 0); diff --git a/gas/config/tc-ppc.h b/gas/config/tc-ppc.h index de9522d4bf6..383f71f2189 100644 --- a/gas/config/tc-ppc.h +++ b/gas/config/tc-ppc.h @@ -322,9 +322,12 @@ extern void ppc_frob_label (symbolS *); /* call md_pcrel_from_section, not md_pcrel_from */ #define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from_section(FIX, SEC) +#define md_operand(EXP) ppc_operand (EXP) +extern void (*ppc_operand) (expressionS *exp); + #define md_parse_name(name, exp, mode, c) \ - (ppc_parse_name (name, exp, mode), true) -extern void ppc_parse_name (const char *, struct expressionS *, enum expr_mode); + ((*ppc_parse_name) (name, exp, mode), true) +extern void (*ppc_parse_name) (const char *, struct expressionS *, enum expr_mode); #define md_optimize_expr(left, op, right) ppc_optimize_expr (left, op, right) extern int ppc_optimize_expr (expressionS *, operatorT, expressionS *); @@ -359,6 +362,15 @@ extern void ppc_cfi_frame_initial_instructions (void); #define tc_regname_to_dw2regnum tc_ppc_regname_to_dw2regnum extern int tc_ppc_regname_to_dw2regnum (char *); +/* + * A hint that the operand refers to a vector, like *%r102 or *%f.15. + * Such operand is converted to a usual O_register after it's remapped. + */ +#define O_vector O_md1 + +extern bool ppc_resolve_symbol (symbolS *sym, valueT *val, segT *seg); +#define md_resolve_symbol ppc_resolve_symbol + extern int ppc_cie_data_alignment; extern int ppc_dwarf2_line_min_insn_length; -- 2.30.2