aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-ppc.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2018-08-16 16:14:12 +0930
committerAlan Modra <amodra@gmail.com>2018-08-21 16:05:36 +0930
commit9cf7e5687f823a1009d25cb25ff653ee8372e517 (patch)
tree33fc95350dcbe996766c532ed4349dba4d01e4a0 /gas/config/tc-ppc.c
parent46807bf45106af5523ad06cf84e7b825dcb9f089 (diff)
downloadfsf-binutils-gdb-9cf7e5687f823a1009d25cb25ff653ee8372e517.zip
fsf-binutils-gdb-9cf7e5687f823a1009d25cb25ff653ee8372e517.tar.gz
fsf-binutils-gdb-9cf7e5687f823a1009d25cb25ff653ee8372e517.tar.bz2
Use operand->extract to provide defaults for optional PowerPC operands
Most optional operands to powerpc instructions use a default value of zero, but there are a few exceptions. Those have been handled by PPC_OPERAND_OPTIONAL_VALUE and an entry in the powerpc_operands table for the default value, smuggled in the shift field. This patch changes that to using the operand extract function to provide non-zero defaults. I've also moved the code determining whether optional operands are provided or omitted, to the point the first optional operand is seen, and allowed for the possibility of optional base register operands in a future patch. The patch does change the error you get on invalid assembly like ld 3,4 You'll now see "missing operand" rather than "syntax error; end of line, expected `('". gas/ * config/tc-ppc.c (md_assemble): Delay counting of optional operands until one is encountered. Allow for the possibility of optional base regs, ie. PPC_OPERAND_PARENS. Call ppc_optional_operand_value with extra args. include/ * opcode/ppc.h (struct powerpc_operand): Correct "insert" comment. Mention use of "extract" function to provide default value. (PPC_OPERAND_OPTIONAL_VALUE): Delete. (ppc_optional_operand_value): Rewrite to use extract function. opcodes/ * ppc-dis.c (operand_value_powerpc): Init "invalid". (skip_optional_operands): Count optional operands, and update ppc_optional_operand_value call. * ppc-opc.c (extract_dxdn): Remove ATTRIBUTE_UNUSED from used arg. (extract_vlensi): Likewise. (extract_fxm): Return default value for missing optional operand. (extract_ls, extract_raq, extract_tbr): Likewise. (insert_sxl, extract_sxl): New functions. (insert_esync, extract_esync): Remove Power9 handling and simplify. (powerpc_operands <FXM4, TBR>): Delete PPC_OPERAND_OPTIONAL_VALUE flag and extra entry. (powerpc_operands <SXL>): Likewise, and use insert_sxl and extract_sxl.
Diffstat (limited to 'gas/config/tc-ppc.c')
-rw-r--r--gas/config/tc-ppc.c152
1 files changed, 74 insertions, 78 deletions
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 6135cb4..d4cc2ff 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -2745,7 +2745,6 @@ md_assemble (char *str)
const struct powerpc_opcode *opcode;
uint64_t insn;
const unsigned char *opindex_ptr;
- int skip_optional;
int need_paren;
int next_opindex;
struct ppc_fixup fixups[MAX_INSN_FIXUPS];
@@ -2783,55 +2782,11 @@ md_assemble (char *str)
++str;
/* PowerPC operands are just expressions. The only real issue is
- that a few operand types are optional. All cases which might use
- an optional operand separate the operands only with commas (in some
- cases parentheses are used, as in ``lwz 1,0(1)'' but such cases never
- have optional operands). Most instructions with optional operands
- have only one. Those that have more than one optional operand can
- take either all their operands or none. So, before we start seriously
- parsing the operands, we check to see if we have optional operands,
- and if we do, we count the number of commas to see which operands
- have been omitted. */
- skip_optional = 0;
- for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)
- {
- const struct powerpc_operand *operand;
-
- operand = &powerpc_operands[*opindex_ptr];
- if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
- && !((operand->flags & PPC_OPERAND_OPTIONAL32) != 0 && ppc_obj64))
- {
- unsigned int opcount;
- unsigned int num_operands_expected;
-
- /* There is an optional operand. Count the number of
- commas in the input line. */
- if (*str == '\0')
- opcount = 0;
- else
- {
- opcount = 1;
- s = str;
- while ((s = strchr (s, ',')) != (char *) NULL)
- {
- ++opcount;
- ++s;
- }
- }
-
- /* Compute the number of expected operands. */
- for (num_operands_expected = 0, i = 0; opcode->operands[i]; i ++)
- ++ num_operands_expected;
-
- /* If there are fewer operands in the line then are called
- for by the instruction, we want to skip the optional
- operands. */
- if (opcount < num_operands_expected)
- skip_optional = 1;
-
- break;
- }
- }
+ that a few operand types are optional. If an instruction has
+ multiple optional operands and one is omitted, then all optional
+ operands past the first omitted one must also be omitted. */
+ int num_optional_operands = 0;
+ int num_optional_provided = 0;
/* Gather the operands. */
need_paren = 0;
@@ -2855,26 +2810,66 @@ md_assemble (char *str)
errmsg = NULL;
/* If this is an optional operand, and we are skipping it, just
- insert a zero. */
+ insert the default value, usually a zero. */
if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
- && !((operand->flags & PPC_OPERAND_OPTIONAL32) != 0 && ppc_obj64)
- && skip_optional)
+ && !((operand->flags & PPC_OPERAND_OPTIONAL32) != 0 && ppc_obj64))
{
- int64_t val = ppc_optional_operand_value (operand);
- if (operand->insert)
+ if (num_optional_operands == 0)
{
- insn = (*operand->insert) (insn, val, ppc_cpu, &errmsg);
- if (errmsg != (const char *) NULL)
- as_bad ("%s", errmsg);
+ const unsigned char *optr;
+ int total = 0;
+ int provided = 0;
+ int omitted;
+
+ s = str;
+ for (optr = opindex_ptr; *optr != 0; optr++)
+ {
+ const struct powerpc_operand *op;
+ op = &powerpc_operands[*optr];
+
+ ++total;
+
+ if ((op->flags & PPC_OPERAND_OPTIONAL) != 0
+ && !((op->flags & PPC_OPERAND_OPTIONAL32) != 0
+ && ppc_obj64))
+ ++num_optional_operands;
+
+ if (s != NULL && *s != '\0')
+ {
+ ++provided;
+
+ /* Look for the start of the next operand. */
+ if ((op->flags & PPC_OPERAND_PARENS) != 0)
+ s = strpbrk (s, "(,");
+ else
+ s = strchr (s, ',');
+
+ if (s != NULL)
+ ++s;
+ }
+ }
+ omitted = total - provided;
+ num_optional_provided = num_optional_operands - omitted;
}
- else if (operand->shift >= 0)
- insn |= (val & operand->bitm) << operand->shift;
- else
- insn |= (val & operand->bitm) >> -operand->shift;
+ if (--num_optional_provided < 0)
+ {
+ int64_t val = ppc_optional_operand_value (operand, insn, ppc_cpu,
+ num_optional_provided);
+ if (operand->insert)
+ {
+ insn = (*operand->insert) (insn, val, ppc_cpu, &errmsg);
+ if (errmsg != (const char *) NULL)
+ as_bad ("%s", errmsg);
+ }
+ else if (operand->shift >= 0)
+ insn |= (val & operand->bitm) << operand->shift;
+ else
+ insn |= (val & operand->bitm) >> -operand->shift;
- if ((operand->flags & PPC_OPERAND_NEXT) != 0)
- next_opindex = *opindex_ptr + 1;
- continue;
+ if ((operand->flags & PPC_OPERAND_NEXT) != 0)
+ next_opindex = *opindex_ptr + 1;
+ continue;
+ }
}
/* Gather the operand. */
@@ -3448,27 +3443,28 @@ md_assemble (char *str)
}
}
else if ((operand->flags & PPC_OPERAND_PARENS) != 0)
- {
- endc = '(';
- need_paren = 1;
- }
+ endc = '(';
else
endc = ',';
/* The call to expression should have advanced str past any
whitespace. */
- if (*str != endc
- && (endc != ',' || *str != '\0'))
+ if (*str == endc)
{
- if (*str == '\0')
- as_bad (_("syntax error; end of line, expected `%c'"), endc);
- else
- as_bad (_("syntax error; found `%c', expected `%c'"), *str, endc);
+ ++str;
+ if (endc == '(')
+ need_paren = 1;
+ }
+ else if (*str != '\0')
+ {
+ as_bad (_("syntax error; found `%c', expected `%c'"), *str, endc);
+ break;
+ }
+ else if (endc == ')')
+ {
+ as_bad (_("syntax error; end of line, expected `%c'"), endc);
break;
}
-
- if (*str != '\0')
- ++str;
}
while (ISSPACE (*str))