|
|
commit 11a0cf2ec0ed6e70ff25e9a50c2223dcd98c1c10 |
|
|
Author: Peter Bergner <bergner@vnet.ibm.com> |
|
|
Date: Fri Jun 19 17:17:07 2015 -0500 |
|
|
|
|
|
Allow for optional operands with non-zero default values. |
|
|
|
|
|
ISA 2.07 (ie, POWER8) added the rfebb instruction which takes one operand |
|
|
with the value of either a 0 or 1. It also defines an extended mnemonic |
|
|
with no operands (ie, "rfebb") that is supposed to be equivalent to "rfebb 1". |
|
|
I implemented rfebb's lone operand with PPC_OPERAND_OPTIONAL, but the |
|
|
problem is, optional operands that are ommitted always default to the |
|
|
value 0, which is wrong in this case. I have added support for allowing |
|
|
non-zero default values by adding an additional flag PPC_OPERAND_OPTIONAL_VALUE |
|
|
that specifies that the default operand value to be used is stored in the |
|
|
SHIFT field of the operand field immediately following this one. |
|
|
|
|
|
This fixes the rfebb issue. I also fixed the mftb and mfcr instructions |
|
|
so they use the same mechanism. This allows us to flag invalid uses of |
|
|
mfcr where we explicitly pass in a zero FXM value, like the use in a2.[sd]. |
|
|
|
|
|
include/opcode/ |
|
|
|
|
|
* ppc.h (PPC_OPERAND_OPTIONAL_VALUE): New. |
|
|
(ppc_optional_operand_value): New inline function. |
|
|
|
|
|
opcodes/ |
|
|
* ppc-dis.h (skip_optional_operands): Use ppc_optional_operand_value. |
|
|
* ppc-opc.c (FXM4): Add non-zero optional value. |
|
|
(TBR): Likewise. |
|
|
(SXL): Likewise. |
|
|
(insert_fxm): Handle new default operand value. |
|
|
(extract_fxm): Likewise. |
|
|
(insert_tbr): Likewise. |
|
|
(extract_tbr): Likewise. |
|
|
|
|
|
gas/ |
|
|
* config/tc-ppc.c (md_assemble): Use ppc_optional_operand_value. |
|
|
Allow for optional operands without insert functions. |
|
|
|
|
|
gas/testsuite/ |
|
|
* gas/ppc/power8.d: Fixup rfebb test results. |
|
|
* gas/ppc/a2.s: Fix invalid mfcr test. |
|
|
* gas/ppc/a2.d: Likewise. |
|
|
|
|
|
### a/include/opcode/ChangeLog |
|
|
### b/include/opcode/ChangeLog |
|
|
## -1,3 +1,8 @@ |
|
|
+2015-06-19 Peter Bergner <bergner@vnet.ibm.com> |
|
|
+ |
|
|
+ * ppc.h (PPC_OPERAND_OPTIONAL_VALUE): New. |
|
|
+ (ppc_optional_operand_value): New inline function. |
|
|
+ |
|
|
2015-06-04 Matthew Wahab <matthew.wahab@arm.com> |
|
|
|
|
|
* aarch64.h (AARCH64_V8_1): New. |
|
|
--- a/include/opcode/ppc.h |
|
|
+++ b/include/opcode/ppc.h |
|
|
@@ -380,6 +380,11 @@ extern const unsigned int num_powerpc_operands; |
|
|
|
|
|
/* This is a CR FIELD that does not use symbolic names. */ |
|
|
#define PPC_OPERAND_CR_REG (0x200000) |
|
|
+ |
|
|
+/* This flag is only used with PPC_OPERAND_OPTIONAL. If this operand |
|
|
+ is omitted, then the value it should use for the operand is stored |
|
|
+ in the SHIFT field of the immediatly following operand field. */ |
|
|
+#define PPC_OPERAND_OPTIONAL_VALUE (0x400000) |
|
|
|
|
|
/* The POWER and PowerPC assemblers use a few macros. We keep them |
|
|
with the operands table for simplicity. The macro table is an |
|
|
@@ -409,4 +414,12 @@ extern const int powerpc_num_macros; |
|
|
|
|
|
extern ppc_cpu_t ppc_parse_cpu (ppc_cpu_t, ppc_cpu_t *, const char *); |
|
|
|
|
|
+static inline long |
|
|
+ppc_optional_operand_value (const struct powerpc_operand *operand) |
|
|
+{ |
|
|
+ if ((operand->flags & PPC_OPERAND_OPTIONAL_VALUE) != 0) |
|
|
+ return (operand+1)->shift; |
|
|
+ return 0; |
|
|
+} |
|
|
+ |
|
|
#endif /* PPC_H */ |
|
|
### a/opcodes/ChangeLog |
|
|
### b/opcodes/ChangeLog |
|
|
## -1,3 +1,14 @@ |
|
|
+2015-06-19 Peter Bergner <bergner@vnet.ibm.com> |
|
|
+ |
|
|
+ * ppc-dis.h (skip_optional_operands): Use ppc_optional_operand_value. |
|
|
+ * ppc-opc.c (FXM4): Add non-zero optional value. |
|
|
+ (TBR): Likewise. |
|
|
+ (SXL): Likewise. |
|
|
+ (insert_fxm): Handle new default operand value. |
|
|
+ (extract_fxm): Likewise. |
|
|
+ (insert_tbr): Likewise. |
|
|
+ (extract_tbr): Likewise. |
|
|
+ |
|
|
2015-06-16 Matthew Wahab <matthew.wahab@arm.com> |
|
|
|
|
|
* arch64-opc.c (aarch64_sys_regs): Add "id_mmfr4_el1". |
|
|
--- a/opcodes/ppc-dis.c |
|
|
+++ b/opcodes/ppc-dis.c |
|
|
@@ -452,7 +452,8 @@ skip_optional_operands (const unsigned char *opindex, |
|
|
operand = &powerpc_operands[*opindex]; |
|
|
if ((operand->flags & PPC_OPERAND_NEXT) != 0 |
|
|
|| ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 |
|
|
- && operand_value_powerpc (operand, insn, dialect) != 0)) |
|
|
+ && operand_value_powerpc (operand, insn, dialect) != |
|
|
+ ppc_optional_operand_value (operand))) |
|
|
return 0; |
|
|
} |
|
|
|
|
|
--- a/opcodes/ppc-opc.c |
|
|
+++ b/opcodes/ppc-opc.c |
|
|
@@ -382,10 +382,12 @@ const struct powerpc_operand powerpc_operands[] = |
|
|
|
|
|
/* Power4 version for mfcr. */ |
|
|
#define FXM4 FXM + 1 |
|
|
- { 0xff, 12, insert_fxm, extract_fxm, PPC_OPERAND_OPTIONAL }, |
|
|
+ { 0xff, 12, insert_fxm, extract_fxm, PPC_OPERAND_OPTIONAL | PPC_OPERAND_OPTIONAL_VALUE}, |
|
|
+ /* If the FXM4 operand is ommitted, use the sentinel value -1. */ |
|
|
+ { -1, -1, NULL, NULL, 0}, |
|
|
|
|
|
/* The IMM20 field in an LI instruction. */ |
|
|
-#define IMM20 FXM4 + 1 |
|
|
+#define IMM20 FXM4 + 2 |
|
|
{ 0xfffff, PPC_OPSHIFT_INV, insert_li20, extract_li20, PPC_OPERAND_SIGNED}, |
|
|
|
|
|
/* The L field in a D or X form instruction. */ |
|
|
@@ -642,10 +644,12 @@ const struct powerpc_operand powerpc_operands[] = |
|
|
/* The TBR field in an XFX form instruction. This is like the SPR |
|
|
field, but it is optional. */ |
|
|
#define TBR SV + 1 |
|
|
- { 0x3ff, 11, insert_tbr, extract_tbr, PPC_OPERAND_OPTIONAL }, |
|
|
+ { 0x3ff, 11, insert_tbr, extract_tbr, PPC_OPERAND_OPTIONAL | PPC_OPERAND_OPTIONAL_VALUE}, |
|
|
+ /* If the TBR operand is ommitted, use the value 268. */ |
|
|
+ { -1, 268, NULL, NULL, 0}, |
|
|
|
|
|
/* The TO field in a D or X form instruction. */ |
|
|
-#define TO TBR + 1 |
|
|
+#define TO TBR + 2 |
|
|
#define DUI TO |
|
|
#define TO_MASK (0x1f << 21) |
|
|
{ 0x1f, 21, NULL, NULL, 0 }, |
|
|
@@ -766,10 +770,12 @@ const struct powerpc_operand powerpc_operands[] = |
|
|
|
|
|
/* The S field in a XL form instruction. */ |
|
|
#define SXL S + 1 |
|
|
- { 0x1, 11, NULL, NULL, PPC_OPERAND_OPTIONAL }, |
|
|
+ { 0x1, 11, NULL, NULL, PPC_OPERAND_OPTIONAL | PPC_OPERAND_OPTIONAL_VALUE}, |
|
|
+ /* If the SXL operand is ommitted, use the value 1. */ |
|
|
+ { -1, 1, NULL, NULL, 0}, |
|
|
|
|
|
/* SH field starting at bit position 16. */ |
|
|
-#define SH16 SXL + 1 |
|
|
+#define SH16 SXL + 2 |
|
|
/* The DCM and DGM fields in a Z form instruction. */ |
|
|
#define DCM SH16 |
|
|
#define DGM DCM |
|
|
@@ -1284,19 +1290,13 @@ insert_fxm (unsigned long insn, |
|
|
} |
|
|
} |
|
|
|
|
|
- /* If the optional field on mfcr is missing that means we want to use |
|
|
- the old form of the instruction that moves the whole cr. In that |
|
|
- case we'll have VALUE zero. There doesn't seem to be a way to |
|
|
- distinguish this from the case where someone writes mfcr %r3,0. */ |
|
|
- else if (value == 0) |
|
|
- ; |
|
|
- |
|
|
/* If only one bit of the FXM field is set, we can use the new form |
|
|
of the instruction, which is faster. Unlike the Power4 branch hint |
|
|
encoding, this is not backward compatible. Do not generate the |
|
|
new form unless -mpower4 has been given, or -many and the two |
|
|
operand form of mfcr was used. */ |
|
|
- else if ((value & -value) == value |
|
|
+ else if (value > 0 |
|
|
+ && (value & -value) == value |
|
|
&& ((dialect & PPC_OPCODE_POWER4) != 0 |
|
|
|| ((dialect & PPC_OPCODE_ANY) != 0 |
|
|
&& (insn & (0x3ff << 1)) == 19 << 1))) |
|
|
@@ -1305,7 +1305,10 @@ insert_fxm (unsigned long insn, |
|
|
/* Any other value on mfcr is an error. */ |
|
|
else if ((insn & (0x3ff << 1)) == 19 << 1) |
|
|
{ |
|
|
- *errmsg = _("ignoring invalid mfcr mask"); |
|
|
+ /* A value of -1 means we used the one operand form of |
|
|
+ mfcr which is valid. */ |
|
|
+ if (value != -1) |
|
|
+ *errmsg = _("ignoring invalid mfcr mask"); |
|
|
value = 0; |
|
|
} |
|
|
|
|
|
@@ -1332,6 +1335,8 @@ extract_fxm (unsigned long insn, |
|
|
{ |
|
|
if (mask != 0) |
|
|
*invalid = 1; |
|
|
+ else |
|
|
+ mask = -1; |
|
|
} |
|
|
|
|
|
return mask; |
|
|
@@ -1868,12 +1873,7 @@ extract_sprg (unsigned long insn, |
|
|
} |
|
|
|
|
|
/* The TBR field in an XFX instruction. This is just like SPR, but it |
|
|
- is optional. When TBR is omitted, it must be inserted as 268 (the |
|
|
- magic number of the TB register). These functions treat 0 |
|
|
- (indicating an omitted optional operand) as 268. This means that |
|
|
- ``mftb 4,0'' is not handled correctly. This does not matter very |
|
|
- much, since the architecture manual does not define mftb as |
|
|
- accepting any values other than 268 or 269. */ |
|
|
+ is optional. */ |
|
|
|
|
|
static unsigned long |
|
|
insert_tbr (unsigned long insn, |
|
|
@@ -1881,8 +1881,6 @@ insert_tbr (unsigned long insn, |
|
|
ppc_cpu_t dialect ATTRIBUTE_UNUSED, |
|
|
const char **errmsg) |
|
|
{ |
|
|
- if (value == 0) |
|
|
- value = 268; |
|
|
if (value != 268 && value != 269) |
|
|
*errmsg = _("invalid tbr number"); |
|
|
return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6); |
|
|
@@ -1898,8 +1896,6 @@ extract_tbr (unsigned long insn, |
|
|
ret = ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0); |
|
|
if (ret != 268 && ret != 269) |
|
|
*invalid = 1; |
|
|
- if (ret == 268) |
|
|
- ret = 0; |
|
|
return ret; |
|
|
} |
|
|
|
|
|
|