[1/5] PowerPC add initial -mfuture instruction support

Message ID 20190524013332.GD6820@bubble.grove.modra.org
State New
Headers show
Series
  • PowerPC -mfuture support
Related show

Commit Message

Alan Modra May 24, 2019, 1:33 a.m.
This patch adds initial 64-bit insn assembler/disassembler support.
The only instruction added is "pnop" along with the automatic aligning
of prefix instruction so they do not cross 64-byte boundaries.

include/
	* dis-asm.h (WIDE_OUTPUT): Define.
	* opcode/ppc.h (prefix_opcodes, prefix_num_opcodes): Declare.
	(PPC_OPCODE_POWERXX, PPC_GET_PREFIX, PPC_GET_SUFFIX),
	(PPC_PREFIX_P, PPC_PREFIX_SEG): Define.
opcodes/
	* ppc-dis.c (ppc_opts): Add "future" entry.
	(PREFIX_OPCD_SEGS): Define.
	(prefix_opcd_indices): New array.
	(disassemble_init_powerpc): Initialize prefix_opcd_indices.
	(lookup_prefix): New function.
	(print_insn_powerpc): Handle 64-bit prefix instructions.
	* ppc-opc.c (PREFIX_OP, PREFIX_FORM, SUFFIX_MASK, PREFIX_MASK),
	(PMRR, POWERXX): Define.
	(prefix_opcodes): New instruction table.
	(prefix_num_opcodes): New constant.
binutils/
	* objdump.c (disassemble_bytes): Set WIDE_OUTPUT in flags.
gas/
	* config/tc-ppc.c (ppc_setup_opcodes): Handle prefix_opcodes.
	(struct insn_label_list): New.
	(insn_labels, free_insn_labels): New variables.
	(ppc_record_label, ppc_clear_labels, ppc_start_line_hook): New funcs.
	(ppc_frob_label, ppc_new_dot_label): Move functions earlier in file
	and call ppc_record_label.
	(md_assemble): Handle 64-bit prefix instructions.  Align labels
	that are on the same line as a prefix instruction.
	* config/tc-ppc.h (tc_frob_label, ppc_frob_label): Move to
	later in the file.
	(md_start_line_hook): Define.
	(ppc_start_line_hook): Declare.
	* testsuite/gas/ppc/prefix-align.d,
	* testsuite/gas/ppc/prefix-align.s: New test.
	* testsuite/gas/ppc/ppc.exp: Run new test.


-- 
Alan Modra
Australia Development Lab, IBM

Comments

Jan Beulich June 2, 2019, 6:33 a.m. | #1
Alan,

>>> Alan Modra <amodra@gmail.com> 05/24/19 3:33 AM >>>

>@@ -376,6 +381,8 @@ powerpc_init_dialect (struct disassemble_info *info)

 >

>#define PPC_OPCD_SEGS (1 + PPC_OP (-1))

>static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS + 1];

>+#define PREFIX_OPCD_SEGS (1 + PPC_PREFIX_SEG (-1))

>+static unsigned short prefix_opcd_indices[PPC_OPCD_SEGS+1];


Isn't the array dimension a copy-and-paste mistake, i.e. shouldn't it be
PREFIX_OPCD_SEGS + 1 ?

Jan
Alan Modra June 3, 2019, 2:26 a.m. | #2
On Sun, Jun 02, 2019 at 12:33:15AM -0600, Jan Beulich wrote:
> Alan,

> 

> >>> Alan Modra <amodra@gmail.com> 05/24/19 3:33 AM >>>

> >@@ -376,6 +381,8 @@ powerpc_init_dialect (struct disassemble_info *info)

>  >

> >#define PPC_OPCD_SEGS (1 + PPC_OP (-1))

> >static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS + 1];

> >+#define PREFIX_OPCD_SEGS (1 + PPC_PREFIX_SEG (-1))

> >+static unsigned short prefix_opcd_indices[PPC_OPCD_SEGS+1];

> 

> Isn't the array dimension a copy-and-paste mistake, i.e. shouldn't it be

> PREFIX_OPCD_SEGS + 1 ?


Thanks Jan, yes the array size should be smaller.

	* ppc-dis.c (prefix_opcd_indices): Correct size.

diff --git a/opcodes/ppc-dis.c b/opcodes/ppc-dis.c
index 9334be2138..2f5756b6cc 100644
--- a/opcodes/ppc-dis.c
+++ b/opcodes/ppc-dis.c
@@ -382,7 +382,7 @@ powerpc_init_dialect (struct disassemble_info *info)
 #define PPC_OPCD_SEGS (1 + PPC_OP (-1))
 static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS + 1];
 #define PREFIX_OPCD_SEGS (1 + PPC_PREFIX_SEG (-1))
-static unsigned short prefix_opcd_indices[PPC_OPCD_SEGS+1];
+static unsigned short prefix_opcd_indices[PREFIX_OPCD_SEGS + 1];
 #define VLE_OPCD_SEGS (1 + VLE_OP_TO_SEG (VLE_OP (-1, 0xffff)))
 static unsigned short vle_opcd_indices[VLE_OPCD_SEGS + 1];
 #define SPE2_OPCD_SEGS (1 + SPE2_XOP_TO_SEG (SPE2_XOP (-1)))

-- 
Alan Modra
Australia Development Lab, IBM
Jan Beulich June 20, 2019, 12:09 p.m. | #3
>>> Alan Modra <amodra@gmail.com> 05/24/19 3:33 AM >>>

>--- a/opcodes/ppc-opc.c

>+++ b/opcodes/ppc-opc.c

>@@ -2721,6 +2721,18 @@ const unsigned int num_powerpc_operands = (sizeof (powerpc_operands)

>#define OP(x) ((((uint64_t)(x)) & 0x3f) << 26)

>#define OP_MASK OP (0x3f)

 >

>+/* The prefix opcode.  */

>+#define PREFIX_OP (1ULL << 58)

>+

>+/* The 2-bit prefix form.  */

>+#define PREFIX_FORM(x) ((x & 3ULL) << 56)

>+

>+#define SUFFIX_MASK ((1ULL << 32) - 1)

>+#define PREFIX_MASK (SUFFIX_MASK << 32)


With these, am I right in understanding that ...


>@@ -7796,6 +7809,17 @@ const struct powerpc_opcode powerpc_opcodes[] = {

>const unsigned int powerpc_num_opcodes =

>sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);

  >

>+/* The opcode table for 8-byte prefix instructions.

>+

>+   The format of this opcode table is the same as the main opcode table.  */

>+

>+const struct powerpc_opcode prefix_opcodes[] = {

>+{"pnop",	  PMRR,		       PREFIX_MASK,	POWERXX, 0,	{0}},


... everything with the 32 prefix bits matching the pattern decodes to PNOP, regardless of
any of the 32 suffix bits? The testcase added covers only the case of the suffix bits all being
zero.


Jan
Alan Modra June 20, 2019, 1:31 p.m. | #4
On Thu, Jun 20, 2019 at 06:09:07AM -0600, Jan Beulich wrote:
> >>> Alan Modra <amodra@gmail.com> 05/24/19 3:33 AM >>>

> >--- a/opcodes/ppc-opc.c

> >+++ b/opcodes/ppc-opc.c

> >@@ -2721,6 +2721,18 @@ const unsigned int num_powerpc_operands = (sizeof (powerpc_operands)

> >#define OP(x) ((((uint64_t)(x)) & 0x3f) << 26)

> >#define OP_MASK OP (0x3f)

>  >

> >+/* The prefix opcode.  */

> >+#define PREFIX_OP (1ULL << 58)

> >+

> >+/* The 2-bit prefix form.  */

> >+#define PREFIX_FORM(x) ((x & 3ULL) << 56)

> >+

> >+#define SUFFIX_MASK ((1ULL << 32) - 1)

> >+#define PREFIX_MASK (SUFFIX_MASK << 32)

> 

> With these, am I right in understanding that ...

> 

> 

> >@@ -7796,6 +7809,17 @@ const struct powerpc_opcode powerpc_opcodes[] = {

> >const unsigned int powerpc_num_opcodes =

> >sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);

>   >

> >+/* The opcode table for 8-byte prefix instructions.

> >+

> >+   The format of this opcode table is the same as the main opcode table.  */

> >+

> >+const struct powerpc_opcode prefix_opcodes[] = {

> >+{"pnop",	  PMRR,		       PREFIX_MASK,	POWERXX, 0,	{0}},

> 

> ... everything with the 32 prefix bits matching the pattern decodes to PNOP, regardless of

> any of the 32 suffix bits? The testcase added covers only the case of the suffix bits all being

> zero.


Yes the suffix word is don't care with one restriction, which we
haven't implemented in binutils yet.  It can't be a branch instruction
encoding.

-- 
Alan Modra
Australia Development Lab, IBM
Alan Modra June 20, 2019, 1:40 p.m. | #5
On Thu, Jun 20, 2019 at 11:01:03PM +0930, Alan Modra wrote:
> Yes the suffix word is don't care with one restriction, which we

> haven't implemented in binutils yet.  It can't be a branch instruction

> encoding.


Well, that's the thinking now.  As with all of the -mfuture support
everything is subject to change so there isn't much reason to
implement the restriction at this point.

-- 
Alan Modra
Australia Development Lab, IBM

Patch

diff --git a/binutils/objdump.c b/binutils/objdump.c
index 05d503e514..7381e4885d 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -1946,7 +1946,8 @@  disassemble_bytes (struct disassemble_info * inf,
 	      inf->stream = &sfile;
 	      inf->bytes_per_line = 0;
 	      inf->bytes_per_chunk = 0;
-	      inf->flags = disassemble_all ? DISASSEMBLE_DATA : 0;
+	      inf->flags = ((disassemble_all ? DISASSEMBLE_DATA : 0)
+			    | (wide_output ? WIDE_OUTPUT : 0));
 	      if (machine)
 		inf->flags |= USER_SPECIFIED_MACHINE_TYPE;
 
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index d5d51f78f3..4abb5b8a31 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -1673,6 +1673,50 @@  ppc_setup_opcodes (void)
     for (op = powerpc_opcodes; op < op_end; op++)
       hash_insert (ppc_hash, op->name, (void *) op);
 
+  op_end = prefix_opcodes + prefix_num_opcodes;
+  for (op = prefix_opcodes; op < op_end; op++)
+    {
+      if (ENABLE_CHECKING)
+	{
+	  unsigned int new_opcode = PPC_PREFIX_SEG (op[0].opcode);
+
+#ifdef PRINT_OPCODE_TABLE
+	  printf ("%-14s\t#%04u\tmajor op/2: 0x%x\top: 0x%llx\tmask: 0x%llx\tflags: 0x%llx\n",
+		  op->name, (unsigned int) (op - prefix_opcodes),
+		  new_opcode, (unsigned long long) op->opcode,
+		  (unsigned long long) op->mask, (unsigned long long) op->flags);
+#endif
+
+	  /* The major opcodes had better be sorted.  Code in the disassembler
+	     assumes the insns are sorted according to major opcode.  */
+	  if (op != prefix_opcodes
+	      && new_opcode < PPC_PREFIX_SEG (op[-1].opcode))
+	    {
+	      as_bad (_("major opcode is not sorted for %s"), op->name);
+	      bad_insn = TRUE;
+	    }
+	  bad_insn |= insn_validate (op);
+	}
+
+      if ((ppc_cpu & op->flags) != 0
+	  && !(ppc_cpu & op->deprecated))
+	{
+	  const char *retval;
+
+	  retval = hash_insert (ppc_hash, op->name, (void *) op);
+	  if (retval != NULL)
+	    {
+	      as_bad (_("duplicate instruction %s"),
+		      op->name);
+	      bad_insn = TRUE;
+	    }
+	}
+    }
+
+  if ((ppc_cpu & PPC_OPCODE_ANY) != 0)
+    for (op = prefix_opcodes; op < op_end; op++)
+      hash_insert (ppc_hash, op->name, (void *) op);
+
   op_end = vle_opcodes + vle_num_opcodes;
   for (op = vle_opcodes; op < op_end; op++)
     {
@@ -2740,6 +2784,90 @@  ppc_apuinfo_section_add (unsigned int apu, unsigned int version)
 #undef APUID
 #endif
 
+/* Various frobbings of labels and their addresses.  */
+
+/* Symbols labelling the current insn.  */
+struct insn_label_list
+{
+  struct insn_label_list *next;
+  symbolS *label;
+};
+
+static struct insn_label_list *insn_labels;
+static struct insn_label_list *free_insn_labels;
+
+static void
+ppc_record_label (symbolS *sym)
+{
+  struct insn_label_list *l;
+
+  if (free_insn_labels == NULL)
+    l = XNEW (struct insn_label_list);
+  else
+    {
+      l = free_insn_labels;
+      free_insn_labels = l->next;
+    }
+
+  l->label = sym;
+  l->next = insn_labels;
+  insn_labels = l;
+}
+
+static void
+ppc_clear_labels (void)
+{
+  while (insn_labels != NULL)
+    {
+      struct insn_label_list *l = insn_labels;
+      insn_labels = l->next;
+      l->next = free_insn_labels;
+      free_insn_labels = l;
+    }
+}
+
+void
+ppc_start_line_hook (void)
+{
+  ppc_clear_labels ();
+}
+
+void
+ppc_new_dot_label (symbolS *sym)
+{
+  ppc_record_label (sym);
+#ifdef OBJ_XCOFF
+  /* Anchor this label to the current csect for relocations.  */
+  symbol_get_tc (sym)->within = ppc_current_csect;
+#endif
+}
+
+void
+ppc_frob_label (symbolS *sym)
+{
+  ppc_record_label (sym);
+
+#ifdef OBJ_XCOFF
+  /* Set the class of a label based on where it is defined.  This handles
+     symbols without suffixes.  Also, move the symbol so that it follows
+     the csect symbol.  */
+  if (ppc_current_csect != (symbolS *) NULL)
+    {
+      if (symbol_get_tc (sym)->symbol_class == -1)
+	symbol_get_tc (sym)->symbol_class = symbol_get_tc (ppc_current_csect)->symbol_class;
+
+      symbol_remove (sym, &symbol_rootP, &symbol_lastP);
+      symbol_append (sym, symbol_get_tc (ppc_current_csect)->within,
+		     &symbol_rootP, &symbol_lastP);
+      symbol_get_tc (ppc_current_csect)->within = sym;
+      symbol_get_tc (sym)->within = ppc_current_csect;
+    }
+#endif
+
+#ifdef OBJ_ELF
+  dwarf2_emit_label (sym);
+#endif
+}
 
 /* We need to keep a list of fixups.  We can't simply generate them as
    we go, because that would require us to first create the frag, and
@@ -3074,6 +3202,7 @@  md_assemble (char *str)
       else
 	ppc_macro (s, macro);
 
+      ppc_clear_labels ();
       return;
     }
 
@@ -3828,14 +3957,50 @@  md_assemble (char *str)
   if ((frag_now_fix () & addr_mask) != 0)
     as_bad (_("instruction address is not a multiple of %d"), addr_mask + 1);
 
-  /* Differentiate between two and four byte insns.  */
+  /* Differentiate between two, four, and eight byte insns.  */
   insn_length = 4;
   if ((ppc_cpu & PPC_OPCODE_VLE) != 0 && PPC_OP_SE_VLE (insn))
     insn_length = 2;
+  else if ((opcode->flags & PPC_OPCODE_POWERXX) != 0
+	   && PPC_PREFIX_P (insn))
+    {
+      struct insn_label_list *l;
+
+      insn_length = 8;
+
+      /* 8-byte prefix instructions are not allowed to cross 64-byte
+	 boundaries.  */
+      frag_align_code (6, 4);
+      record_alignment (now_seg, 6);
+
+      /* Update "dot" in any expressions used by this instruction, and
+	 a label attached to the instruction.  By "attached" we mean
+	 on the same source line as the instruction and without any
+	 intervening semicolons.  */
+      dot_value = frag_now_fix ();
+      dot_frag = frag_now;
+      for (l = insn_labels; l != NULL; l = l->next)
+	{
+	  symbol_set_frag (l->label, dot_frag);
+	  S_SET_VALUE (l->label, dot_value);
+	}
+    }
+
+  ppc_clear_labels ();
 
   f = frag_more (insn_length);
   frag_now->insn_addr = addr_mask;
-  md_number_to_chars (f, insn, insn_length);
+
+  /* The prefix part of an 8-byte instruction always occupies the lower
+     addressed word in a doubleword, regardless of endianness.  */
+  if (!target_big_endian && insn_length == 8)
+    {
+      md_number_to_chars (f, PPC_GET_PREFIX (insn), 4);
+      md_number_to_chars (f + 4, PPC_GET_SUFFIX (insn), 4);
+    }
+  else
+    md_number_to_chars (f, insn, insn_length);
+
   last_insn = insn;
   last_seg = now_seg;
   last_subseg = now_subseg;
@@ -6118,30 +6283,6 @@  ppc_symbol_new_hook (symbolS *sym)
     as_bad (_("unrecognized symbol suffix"));
 }
 
-/* Set the class of a label based on where it is defined.  This
-   handles symbols without suffixes.  Also, move the symbol so that it
-   follows the csect symbol.  */
-
-void
-ppc_frob_label (symbolS *sym)
-{
-  if (ppc_current_csect != (symbolS *) NULL)
-    {
-      if (symbol_get_tc (sym)->symbol_class == -1)
-	symbol_get_tc (sym)->symbol_class = symbol_get_tc (ppc_current_csect)->symbol_class;
-
-      symbol_remove (sym, &symbol_rootP, &symbol_lastP);
-      symbol_append (sym, symbol_get_tc (ppc_current_csect)->within,
-		     &symbol_rootP, &symbol_lastP);
-      symbol_get_tc (ppc_current_csect)->within = sym;
-      symbol_get_tc (sym)->within = ppc_current_csect;
-    }
-
-#ifdef OBJ_ELF
-  dwarf2_emit_label (sym);
-#endif
-}
-
 /* This variable is set by ppc_frob_symbol if any absolute symbols are
    seen.  It tells ppc_adjust_symtab whether it needs to look through
    the symbols.  */
@@ -6673,14 +6814,6 @@  ppc_force_relocation (fixS *fix)
 
   return generic_force_reloc (fix);
 }
-
-void
-ppc_new_dot_label (symbolS *sym)
-{
-  /* Anchor this label to the current csect for relocations.  */
-  symbol_get_tc (sym)->within = ppc_current_csect;
-}
-
 #endif /* OBJ_XCOFF */
 
 #ifdef OBJ_ELF
diff --git a/gas/config/tc-ppc.h b/gas/config/tc-ppc.h
index 84217eabe0..08e381e293 100644
--- a/gas/config/tc-ppc.h
+++ b/gas/config/tc-ppc.h
@@ -171,10 +171,6 @@  extern char *ppc_canonicalize_symbol_name (char *);
 #define tc_symbol_new_hook(sym) ppc_symbol_new_hook (sym)
 extern void ppc_symbol_new_hook (symbolS *);
 
-/* Set the symbol class of a label based on the csect.  */
-#define tc_frob_label(sym) ppc_frob_label (sym)
-extern void ppc_frob_label (symbolS *);
-
 /* TOC relocs requires special handling.  */
 #define tc_fix_adjustable(FIX) ppc_fix_adjustable (FIX)
 extern int ppc_fix_adjustable (struct fix *);
@@ -206,11 +202,11 @@  do {								\
 extern void ppc_xcoff_end (void);
 #define md_end ppc_xcoff_end
 
+#endif /* OBJ_XCOFF */
+
 #define tc_new_dot_label(sym) ppc_new_dot_label (sym)
 extern void ppc_new_dot_label (symbolS *);
 
-#endif /* OBJ_XCOFF */
-
 extern const char       ppc_symbol_chars[];
 #define tc_symbol_chars ppc_symbol_chars
 
@@ -282,6 +278,14 @@  extern int ppc_force_relocation (struct fix *);
 
 #define TC_VALIDATE_FIX_SUB(FIX, SEG) 0
 
+/* Various frobbings of labels and their addresses.  */
+#define md_start_line_hook() ppc_start_line_hook ()
+extern void ppc_start_line_hook (void);
+
+/* Set the symbol class of a label based on the csect.  */
+#define tc_frob_label(sym) ppc_frob_label (sym)
+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)
 extern long md_pcrel_from_section (struct fix *, segT);
diff --git a/gas/testsuite/gas/ppc/ppc.exp b/gas/testsuite/gas/ppc/ppc.exp
index 62d67a391c..6be042bf26 100644
--- a/gas/testsuite/gas/ppc/ppc.exp
+++ b/gas/testsuite/gas/ppc/ppc.exp
@@ -114,3 +114,4 @@  run_dump_test "vsx2"
 run_dump_test "vsx3"
 run_dump_test "htm"
 run_dump_test "titan"
+run_dump_test "prefix-align"
diff --git a/gas/testsuite/gas/ppc/prefix-align.d b/gas/testsuite/gas/ppc/prefix-align.d
new file mode 100644
index 0000000000..b2e1b8374d
--- /dev/null
+++ b/gas/testsuite/gas/ppc/prefix-align.d
@@ -0,0 +1,30 @@ 
+#as: -mfuture
+#objdump: -dr -Mfuture
+#name: POWERXX alignment of labels test
+
+.*
+
+
+Disassembly of section \.text:
+
+0+00 <_start>:
+   0:	(48 00 00 3c|3c 00 00 48) 	b       3c <_start\+0x3c>
+   4:	(48 00 00 3c|3c 00 00 48) 	b       40 <_start\+0x40>
+   8:	(48 00 00 40|40 00 00 48) 	b       48 <_start\+0x48>
+   c:	(7f e0 00 08|08 00 e0 7f) 	trap
+  10:	(7f e0 00 08|08 00 e0 7f) 	trap
+  14:	(7f e0 00 08|08 00 e0 7f) 	trap
+  18:	(7f e0 00 08|08 00 e0 7f) 	trap
+  1c:	(7f e0 00 08|08 00 e0 7f) 	trap
+  20:	(7f e0 00 08|08 00 e0 7f) 	trap
+  24:	(7f e0 00 08|08 00 e0 7f) 	trap
+  28:	(7f e0 00 08|08 00 e0 7f) 	trap
+  2c:	(7f e0 00 08|08 00 e0 7f) 	trap
+  30:	(7f e0 00 08|08 00 e0 7f) 	trap
+  34:	(7f e0 00 08|08 00 e0 7f) 	trap
+  38:	(7f e0 00 08|08 00 e0 7f) 	trap
+  3c:	(60 00 00 00|00 00 00 60) 	nop
+  40:	(07 00 00 00|00 00 00 07) 	pnop
+  44:	(00 00 00 00|00 00 00 00) 
+  48:	(4e 80 00 20|20 00 80 4e) 	blr
+#pass
diff --git a/gas/testsuite/gas/ppc/prefix-align.s b/gas/testsuite/gas/ppc/prefix-align.s
new file mode 100644
index 0000000000..fd0043958b
--- /dev/null
+++ b/gas/testsuite/gas/ppc/prefix-align.s
@@ -0,0 +1,21 @@ 
+	.text
+_start:
+	b 1f;
+	b 2f;
+	b 3f;
+	trap
+	trap
+	trap
+	trap
+	trap
+	trap
+	trap
+	trap
+	trap
+	trap
+	trap
+	trap
+1:
+2:	pnop
+3:
+	blr
diff --git a/include/dis-asm.h b/include/dis-asm.h
index 4e1263c90e..b4d5025811 100644
--- a/include/dis-asm.h
+++ b/include/dis-asm.h
@@ -116,6 +116,8 @@  typedef struct disassemble_info
   /* Set if the user has specifically set the machine type encoded in the
      mach field of this structure.  */
 #define USER_SPECIFIED_MACHINE_TYPE (1 << 29)
+  /* Set if the user has requested wide output.  */
+#define WIDE_OUTPUT (1 << 28)
 
   /* Use internally by the target specific disassembly code.  */
   void *private_data;
diff --git a/include/opcode/ppc.h b/include/opcode/ppc.h
index 7a0bc6030b..314b9b49ff 100644
--- a/include/opcode/ppc.h
+++ b/include/opcode/ppc.h
@@ -68,6 +68,8 @@  struct powerpc_opcode
    instructions.  */
 extern const struct powerpc_opcode powerpc_opcodes[];
 extern const unsigned int powerpc_num_opcodes;
+extern const struct powerpc_opcode prefix_opcodes[];
+extern const unsigned int prefix_num_opcodes;
 extern const struct powerpc_opcode vle_opcodes[];
 extern const unsigned int vle_num_opcodes;
 extern const struct powerpc_opcode spe2_opcodes[];
@@ -226,6 +228,9 @@  extern const unsigned int spe2_num_opcodes;
 /* Opcode is supported by EFS2.  */
 #define PPC_OPCODE_EFS2	    0x200000000000ull
 
+/* Opcode is only supported by powerxx architecture.  */
+#define PPC_OPCODE_POWERXX  0x400000000000ull
+
 /* A macro to extract the major opcode from an instruction.  */
 #define PPC_OP(i) (((i) >> 26) & 0x3f)
 
@@ -243,6 +248,19 @@  extern const unsigned int spe2_num_opcodes;
 
 /* A macro to convert a SPE2 extended opcode to a SPE2 xopcode segment.  */
 #define SPE2_XOP_TO_SEG(i) ((i) >> 7)
+
+/* A macro to extract the prefix word from an 8-byte PREFIX instruction.  */
+#define PPC_GET_PREFIX(i) (((i) >> 32) & ((1LL << 32) - 1))
+
+/* A macro to extract the suffix word from an 8-byte PREFIX instruction.  */
+#define PPC_GET_SUFFIX(i) ((i) & ((1LL << 32) - 1))
+
+/* A macro to determine whether insn I is an 8-byte prefix instruction.  */
+#define PPC_PREFIX_P(i) (PPC_OP (PPC_GET_PREFIX (i)) == 0x1)
+
+/* A macro used to hash 8-byte PREFIX instructions.  */
+#define PPC_PREFIX_SEG(i) (PPC_OP (i) >> 1)
+
 
 /* The operands table is an array of struct powerpc_operand.  */
 
diff --git a/opcodes/ppc-dis.c b/opcodes/ppc-dis.c
index e9e3b3621a..9334be2138 100644
--- a/opcodes/ppc-dis.c
+++ b/opcodes/ppc-dis.c
@@ -185,6 +185,11 @@  struct ppc_mopt ppc_opts[] = {
 		| PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9
 		| PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX),
     0 },
+  { "future",  (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
+		| PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
+		| PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9
+		| PPC_OPCODE_POWERXX | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX),
+    0 },
   { "ppc",     PPC_OPCODE_PPC,
     0 },
   { "ppc32",   PPC_OPCODE_PPC,
@@ -376,6 +381,8 @@  powerpc_init_dialect (struct disassemble_info *info)
 
 #define PPC_OPCD_SEGS (1 + PPC_OP (-1))
 static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS + 1];
+#define PREFIX_OPCD_SEGS (1 + PPC_PREFIX_SEG (-1))
+static unsigned short prefix_opcd_indices[PPC_OPCD_SEGS+1];
 #define VLE_OPCD_SEGS (1 + VLE_OP_TO_SEG (VLE_OP (-1, 0xffff)))
 static unsigned short vle_opcd_indices[VLE_OPCD_SEGS + 1];
 #define SPE2_OPCD_SEGS (1 + SPE2_XOP_TO_SEG (SPE2_XOP (-1)))
@@ -400,6 +407,15 @@  disassemble_init_powerpc (struct disassemble_info *info)
 	      break;
 	}
 
+      /* 64-bit prefix opcodes */
+      for (seg = 0, idx = 0; seg <= PREFIX_OPCD_SEGS; seg++)
+	{
+	  prefix_opcd_indices[seg] = idx;
+	  for (; idx < prefix_num_opcodes; idx++)
+	    if (seg < PPC_PREFIX_SEG (prefix_opcodes[idx].opcode))
+	      break;
+	}
+
       /* VLE opcodes */
       for (seg = 0, idx = 0; seg <= VLE_OPCD_SEGS; seg++)
 	{
@@ -556,6 +572,57 @@  lookup_powerpc (uint64_t insn, ppc_cpu_t dialect)
   return last;
 }
 
+/* Find a match for INSN in the PREFIX opcode table.  */
+
+static const struct powerpc_opcode *
+lookup_prefix (uint64_t insn, ppc_cpu_t dialect)
+{
+  const struct powerpc_opcode *opcode, *opcode_end, *last;
+  unsigned long seg;
+
+  /* Get the opcode segment of the instruction.  */
+  seg = PPC_PREFIX_SEG (insn);
+
+  /* Find the first match in the opcode table for this major opcode.  */
+  opcode_end = prefix_opcodes + prefix_opcd_indices[seg + 1];
+  last = NULL;
+  for (opcode = prefix_opcodes + prefix_opcd_indices[seg];
+       opcode < opcode_end;
+       ++opcode)
+    {
+      const unsigned char *opindex;
+      const struct powerpc_operand *operand;
+      int invalid;
+
+      if ((insn & opcode->mask) != opcode->opcode
+	  || ((dialect & PPC_OPCODE_ANY) == 0
+	      && ((opcode->flags & dialect) == 0
+		  || (opcode->deprecated & dialect) != 0)))
+	continue;
+
+      /* Check validity of operands.  */
+      invalid = 0;
+      for (opindex = opcode->operands; *opindex != 0; opindex++)
+	{
+	  operand = powerpc_operands + *opindex;
+	  if (operand->extract)
+	    (*operand->extract) (insn, dialect, &invalid);
+	}
+      if (invalid)
+	continue;
+
+      if ((dialect & PPC_OPCODE_RAW) == 0)
+	return opcode;
+
+      /* The raw machine insn is one that is not a specialization.  */
+      if (last == NULL
+	  || (last->mask & ~opcode->mask) != 0)
+	last = opcode;
+    }
+
+  return last;
+}
+
 /* Find a match for INSN in the VLE opcode table.  */
 
 static const struct powerpc_opcode *
@@ -699,7 +766,31 @@  print_insn_powerpc (bfd_vma memaddr,
 
   /* Get the major opcode of the insn.  */
   opcode = NULL;
-  if ((dialect & PPC_OPCODE_VLE) != 0)
+  if ((dialect & PPC_OPCODE_POWERXX) != 0
+      && PPC_OP (insn) == 0x1)
+    {
+      uint64_t temp_insn, suffix;
+      status = (*info->read_memory_func) (memaddr + 4, buffer, 4, info);
+      if (status == 0)
+	{
+	  if (bigendian)
+	    suffix = bfd_getb32 (buffer);
+	  else
+	    suffix = bfd_getl32 (buffer);
+	  temp_insn = (insn << 32) | suffix;
+	  opcode = lookup_prefix (temp_insn, dialect & ~PPC_OPCODE_ANY);
+	  if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0)
+	    opcode = lookup_prefix (temp_insn, dialect);
+	  if (opcode != NULL)
+	    {
+	      insn = temp_insn;
+	      insn_length = 8;
+	      if ((info->flags & WIDE_OUTPUT) != 0)
+		info->bytes_per_line = 8;
+	    }
+	}
+    }
+  if (opcode == NULL && (dialect & PPC_OPCODE_VLE) != 0)
     {
       opcode = lookup_vle (insn);
       if (opcode != NULL && PPC_OP_SE_VLE (opcode->mask))
diff --git a/opcodes/ppc-opc.c b/opcodes/ppc-opc.c
index 394a99750c..7dc2d775d9 100644
--- a/opcodes/ppc-opc.c
+++ b/opcodes/ppc-opc.c
@@ -2721,6 +2721,18 @@  const unsigned int num_powerpc_operands = (sizeof (powerpc_operands)
 #define OP(x) ((((uint64_t)(x)) & 0x3f) << 26)
 #define OP_MASK OP (0x3f)
 
+/* The prefix opcode.  */
+#define PREFIX_OP (1ULL << 58)
+
+/* The 2-bit prefix form.  */
+#define PREFIX_FORM(x) ((x & 3ULL) << 56)
+
+#define SUFFIX_MASK ((1ULL << 32) - 1)
+#define PREFIX_MASK (SUFFIX_MASK << 32)
+
+/* Prefix insn, modified register to register form MRR.  */
+#define PMRR (PREFIX_OP | PREFIX_FORM (3))
+
 /* The main opcode combined with a trap code in the TO field of a D
    form instruction.  Used for extended mnemonics for the trap
    instructions.  */
@@ -3547,6 +3559,7 @@  const unsigned int num_powerpc_operands = (sizeof (powerpc_operands)
 #define POWER7	PPC_OPCODE_POWER7
 #define POWER8	PPC_OPCODE_POWER8
 #define POWER9	PPC_OPCODE_POWER9
+#define POWERXX PPC_OPCODE_POWERXX
 #define CELL	PPC_OPCODE_CELL
 #define PPC64	PPC_OPCODE_64 | PPC_OPCODE_64_BRIDGE
 #define NON32	(PPC_OPCODE_64 | PPC_OPCODE_POWER4	\
@@ -7796,6 +7809,17 @@  const struct powerpc_opcode powerpc_opcodes[] = {
 const unsigned int powerpc_num_opcodes =
   sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);
 
+/* The opcode table for 8-byte prefix instructions.
+
+   The format of this opcode table is the same as the main opcode table.  */
+
+const struct powerpc_opcode prefix_opcodes[] = {
+{"pnop",	  PMRR,		       PREFIX_MASK,	POWERXX, 0,	{0}},
+};
+
+const unsigned int prefix_num_opcodes =
+  sizeof (prefix_opcodes) / sizeof (prefix_opcodes[0]);
+
 /* The VLE opcode table.
 
    The format of this opcode table is the same as the main opcode table.  */