#define SVP64_RC1_ACTIVE (1U << 3U)
#define SVP64_RC1_INVERT (SVP64_RC1_ACTIVE | (1U << 4U))
+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(...) \
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"
/* 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;
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;
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;
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;
}
}
}
}
+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. */
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. */
/* 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;
fc = 0;
for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)
{
+ bool vector;
const struct powerpc_operand *operand;
const char *errmsg;
char *hold;
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;
resolve_register (&ex);
+ 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)
| PPC_OPERAND_VSR | PPC_OPERAND_CR_BIT | PPC_OPERAND_CR_REG
| PPC_OPERAND_SPR | PPC_OPERAND_GQR | PPC_OPERAND_ACC
| PPC_OPERAND_DMR)) != 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);
/* 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 *);
#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;