PowerPC: implement md_operand to parse register names

Allows register names to appear in symbol assignments, so for example
 tocp = %r2
 mr %r3,tocp
now assembles.

	* gas/config/tc-ppc.c (REG_NAME_CNT): Delete, replace uses with
	ARRAY_SIZE.
	(register_name): Rename to..
	(md_operand): ..this.  Only handle %reg.
	(cr_names): Rename to..
	(cr_cond): ..this.  Just keep conditions.
	(ppc_parse_name): Add mode param.  Search both cr_cond and
	pre_defined_registers.  Handle absolute and register symbol
	values here rather than in expr.c:operand().
	(md_assemble): Don't special case register name matching in
	operands, except to set cr_operand as appropriate.
	* gas/config/tc-ppc.h (md_operand): Don't define.
	(md_parse_name, ppc_parse_name): Update.
	* read.c (pseudo_set): Copy over entire O_register value.
	* testsuite/gas/ppc/regsyms.d.
	* testsuite/gas/ppc/regsyms.s: New test.
	* testsuite/gas/ppc/ppc.exp: Run it.
This commit is contained in:
Alan Modra
2022-07-12 11:10:08 +09:30
parent 869fa2b36c
commit 00b37cc41e
6 changed files with 82 additions and 89 deletions

View File

@ -785,8 +785,6 @@ static const struct pd_reg pre_defined_registers[] =
{ "xer", 1, PPC_OPERAND_SPR } { "xer", 1, PPC_OPERAND_SPR }
}; };
#define REG_NAME_CNT (sizeof (pre_defined_registers) / sizeof (struct pd_reg))
/* Given NAME, find the register number associated with that name, return /* Given NAME, find the register number associated with that name, return
the integer value associated with the given name or -1 on failure. */ the integer value associated with the given name or -1 on failure. */
@ -815,76 +813,43 @@ reg_name_search (const struct pd_reg *regs, int regcount, const char *name)
return NULL; return NULL;
} }
/* /* Called for a non-symbol, non-number operand. Handles %reg. */
* Summary of register_name.
*
* in: Input_line_pointer points to 1st char of operand.
*
* out: A expressionS.
* The operand may have been a register: in this case, X_op == O_register,
* X_add_number is set to the register number, and truth is returned.
* Input_line_pointer->(next non-blank) char after operand, or is in its
* original state.
*/
static bool void
register_name (expressionS *expressionP) md_operand (expressionS *expressionP)
{ {
const struct pd_reg *reg; const struct pd_reg *reg;
char *name; char *name;
char *start; char *start;
char c; char c;
/* Find the spelling of the operand. */ if (input_line_pointer[0] != '%' || !ISALPHA (input_line_pointer[1]))
start = name = input_line_pointer; return;
if (name[0] == '%' && ISALPHA (name[1]))
name = ++input_line_pointer;
else if (!reg_names_p || !ISALPHA (name[0])) start = input_line_pointer;
return false; ++input_line_pointer;
c = get_symbol_name (&name); c = get_symbol_name (&name);
reg = reg_name_search (pre_defined_registers, REG_NAME_CNT, name); reg = reg_name_search (pre_defined_registers,
ARRAY_SIZE (pre_defined_registers), name);
/* Put back the delimiting char. */
*input_line_pointer = c; *input_line_pointer = c;
/* Look to see if it's in the register table. */
if (reg != NULL) if (reg != NULL)
{ {
expressionP->X_op = O_register; expressionP->X_op = O_register;
expressionP->X_add_number = reg->value; expressionP->X_add_number = reg->value;
expressionP->X_md = reg->flags; expressionP->X_md = reg->flags;
/* Make the rest nice. */
expressionP->X_add_symbol = NULL;
expressionP->X_op_symbol = NULL;
return true;
} }
else
/* Reset the line as if we had not done anything. */ input_line_pointer = start;
input_line_pointer = start;
return false;
} }
/* This function is called for each symbol seen in an expression. It
handles the special parsing which PowerPC assemblers are supposed
to use for condition codes. */
/* Whether to do the special parsing. */ /* Whether to do the special parsing. */
static bool cr_operand; static bool cr_operand;
/* Names to recognize in a condition code. This table is sorted. */ /* Extra names to recognise in a condition code. This table is sorted. */
static const struct pd_reg cr_names[] = static const struct pd_reg cr_cond[] =
{ {
{ "cr0", 0, PPC_OPERAND_CR_REG },
{ "cr1", 1, PPC_OPERAND_CR_REG },
{ "cr2", 2, PPC_OPERAND_CR_REG },
{ "cr3", 3, PPC_OPERAND_CR_REG },
{ "cr4", 4, PPC_OPERAND_CR_REG },
{ "cr5", 5, PPC_OPERAND_CR_REG },
{ "cr6", 6, PPC_OPERAND_CR_REG },
{ "cr7", 7, PPC_OPERAND_CR_REG },
{ "eq", 2, PPC_OPERAND_CR_BIT }, { "eq", 2, PPC_OPERAND_CR_BIT },
{ "gt", 1, PPC_OPERAND_CR_BIT }, { "gt", 1, PPC_OPERAND_CR_BIT },
{ "lt", 0, PPC_OPERAND_CR_BIT }, { "lt", 0, PPC_OPERAND_CR_BIT },
@ -892,29 +857,60 @@ static const struct pd_reg cr_names[] =
{ "un", 3, PPC_OPERAND_CR_BIT } { "un", 3, PPC_OPERAND_CR_BIT }
}; };
/* Parsing function. This returns non-zero if it recognized an /* This function is called for each symbol seen in an expression. It
expression. */ handles the special parsing which PowerPC assemblers are supposed
to use for condition codes, and recognises other registers when
-mregnames. */
int int
ppc_parse_name (const char *name, expressionS *exp) ppc_parse_name (const char *name, expressionS *exp, enum expr_mode mode)
{ {
const struct pd_reg *reg; const struct pd_reg *reg = NULL;
if (! cr_operand) if (cr_operand)
return 0; 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);
if (reg != NULL)
{
exp->X_op = O_register;
exp->X_add_number = reg->value;
exp->X_md = reg->flags;
return true;
}
if (*name == '%') /* The following replaces code in expr.c operand() after the
++name; md_parse_name call. There is too much difference between targets
reg = reg_name_search (cr_names, sizeof cr_names / sizeof cr_names[0], in the way X_md is used to move this code into expr.c. If you
name); do, you'll get failures on x86 due to uninitialised X_md fields,
if (reg == NULL) failures on alpha and other targets due to creating register
return 0; symbols as O_constant rather than O_register, and failures on arc
and others due to expecting expr() to leave X_md alone. */
symbolS *sym = symbol_find_or_make (name);
exp->X_op = O_register; /* If we have an absolute symbol or a reg, then we know its value
exp->X_add_number = reg->value; now. Copy the symbol value expression to propagate X_md. */
exp->X_md = reg->flags; bool done = false;
if (mode != expr_defer
&& !S_FORCE_RELOC (sym, 0))
{
segT segment = S_GET_SEGMENT (sym);
if (segment == absolute_section || segment == reg_section)
{
resolve_symbol_value (sym);
*exp = *symbol_get_value_expression (sym);
done = true;
}
}
if (!done)
{
exp->X_op = O_symbol;
exp->X_add_symbol = sym;
exp->X_add_number = 0;
}
return 1; return true;
} }
/* Propagate X_md and check register expressions. This is to support /* Propagate X_md and check register expressions. This is to support
@ -3437,25 +3433,10 @@ md_assemble (char *str)
/* Gather the operand. */ /* Gather the operand. */
hold = input_line_pointer; hold = input_line_pointer;
input_line_pointer = str; input_line_pointer = str;
cr_operand = ((operand->flags & PPC_OPERAND_CR_BIT) != 0
if ((reg_names_p || (operand->flags & PPC_OPERAND_CR_REG) != 0);
&& (((operand->flags & PPC_OPERAND_CR_BIT) != 0) expression (&ex);
|| ((operand->flags & PPC_OPERAND_CR_REG) != 0))) cr_operand = false;
|| !register_name (&ex))
{
char save_lex = lex_type['%'];
if (((operand->flags & PPC_OPERAND_CR_REG) != 0)
|| (operand->flags & PPC_OPERAND_CR_BIT) != 0)
{
cr_operand = true;
lex_type['%'] |= LEX_BEGIN_NAME;
}
expression (&ex);
cr_operand = false;
lex_type['%'] = save_lex;
}
str = input_line_pointer; str = input_line_pointer;
input_line_pointer = hold; input_line_pointer = hold;

View File

@ -322,14 +322,12 @@ extern void ppc_frob_label (symbolS *);
/* call md_pcrel_from_section, not md_pcrel_from */ /* call md_pcrel_from_section, not md_pcrel_from */
#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from_section(FIX, SEC) #define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from_section(FIX, SEC)
#define md_parse_name(name, exp, mode, c) ppc_parse_name (name, exp) #define md_parse_name(name, exp, mode, c) ppc_parse_name (name, exp, mode)
extern int ppc_parse_name (const char *, struct expressionS *); extern int ppc_parse_name (const char *, struct expressionS *, enum expr_mode);
#define md_optimize_expr(left, op, right) ppc_optimize_expr (left, op, right) #define md_optimize_expr(left, op, right) ppc_optimize_expr (left, op, right)
extern int ppc_optimize_expr (expressionS *, operatorT, expressionS *); extern int ppc_optimize_expr (expressionS *, operatorT, expressionS *);
#define md_operand(x)
#define md_cleanup() ppc_cleanup () #define md_cleanup() ppc_cleanup ()
extern void ppc_cleanup (void); extern void ppc_cleanup (void);

View File

@ -3934,10 +3934,9 @@ pseudo_set (symbolS *symbolP)
return; return;
} }
#endif #endif
symbol_set_value_expression (symbolP, &exp);
S_SET_SEGMENT (symbolP, reg_section); S_SET_SEGMENT (symbolP, reg_section);
S_SET_VALUE (symbolP, (valueT) exp.X_add_number);
set_zero_frag (symbolP); set_zero_frag (symbolP);
symbol_get_value_expression (symbolP)->X_op = O_register;
break; break;
case O_symbol: case O_symbol:

View File

@ -36,6 +36,7 @@ run_dump_test "bcy"
run_dump_test "bcaterr" run_dump_test "bcaterr"
run_dump_test "bcat" run_dump_test "bcat"
run_dump_test "regnames" run_dump_test "regnames"
run_dump_test "regsyms"
run_dump_test "misalign" run_dump_test "misalign"
run_dump_test "misalign2" run_dump_test "misalign2"
run_dump_test "machine" run_dump_test "machine"

View File

@ -0,0 +1,10 @@
#as: -mregnames
#objdump: -d
.*: file format .*
Disassembly of section \.text:
0+ <.text>:
0: (7c 43 13 78|78 13 43 7c) mr r3,r2
4: (7f c3 f3 78|78 f3 c3 7f) mr r3,r30

View File

@ -0,0 +1,4 @@
tocp = %r2
mr %r3,tocp
x = r30
mr 3,x