[2/5] PowerPC D-form prefixed loads and stores

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

Commit Message

Alan Modra May 24, 2019, 1:34 a.m.
opcodes/
	* ppc-opc.c (insert_d34, extract_d34, insert_nsi34, extract_nsi34),
	(insert_pcrel, extract_pcrel, extract_pcrel0): New functions.
	(extract_esync, extract_raq, extract_tbr, extract_sxl): Comment.
	(powerpc_operands <D34, SI34, NSI34, PRA0, PRAQ, PCREL, PCREL0,
	XTOP>): Define and add entries.
	(P8LS, PMLS, P_D_MASK, P_DRAPCREL_MASK): Define.
	(prefix_opcodes): Add pli, paddi, pla, psubi, plwz, plbz, pstw,
	pstb, plhz, plha, psth, plfs, plfd, pstfs, pstfd, plq, plxsd,
	plxssp, pld, plwa, pstxsd, pstxssp, pstxv, pstd, and pstq.
gas/
	* config/tc-ppc.c (ppc_insert_operand): Only sign extend fields that
	are 32-bits or smaller.
	* messages.c (as_internal_value_out_of_range): Do not truncate
	variables and use BFD_VMA_FMT to print them.
	* testsuite/gas/ppc/prefix-pcrel.s,
	* testsuite/gas/ppc/prefix-pcrel.d: New test.
	* testsuite/gas/ppc/ppc.exp: Run it.


-- 
Alan Modra
Australia Development Lab, IBM

Comments

Jan Beulich June 20, 2019, 12:04 p.m. | #1
>>> Alan Modra <amodra@gmail.com> 05/24/19 3:34 AM >>>

>@@ -7815,6 +7969,32 @@ const unsigned int powerpc_num_opcodes =

 >

>const struct powerpc_opcode prefix_opcodes[] = {

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

>+{"pli",		  PMLS|OP(14),	       P_DRAPCREL_MASK,	POWERXX, 0,	{RT, SI34}},

>+{"paddi",	  PMLS|OP(14),	       P_D_MASK,	POWERXX, 0,	{RT, RA0, SI34, PCREL0}},

>+{"psubi",	  PMLS|OP(14),	       P_D_MASK,	POWERXX, 0,	{RT, RA0, NSI34, PCREL0}},

>+{"pla",		  PMLS|OP(14),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},

>+{"plwz",	  PMLS|OP(32),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},

>+{"plbz",	  PMLS|OP(34),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},

>+{"pstw",	  PMLS|OP(36),	       P_D_MASK,	POWERXX, 0,	{RS, D34, PRA0, PCREL}},

>+{"pstb",	  PMLS|OP(38),	       P_D_MASK,	POWERXX, 0,	{RS, D34, PRA0, PCREL}},

>+{"plhz",	  PMLS|OP(40),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},

>+{"plwa",	  P8LS|OP(41),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},


Comparing with the neighboring ones - isn't this supposed to use PMLS?


>+{"plxsd",	  P8LS|OP(42),	       P_D_MASK,	POWERXX, 0,	{VD, D34, PRA0, PCREL}},

>+{"plha",	  PMLS|OP(42),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},


Judging, most importantly, from this one.

Jan


>+{"plxssp",	  P8LS|OP(43),	       P_D_MASK,	POWERXX, 0,	{VD, D34, PRA0, PCREL}},

>+{"psth",	  PMLS|OP(44),	       P_D_MASK,	POWERXX, 0,	{RS, D34, PRA0, PCREL}},

>+{"pstxsd",	  P8LS|OP(46),	       P_D_MASK,	POWERXX, 0,	{VS, D34, PRA0, PCREL}},

>+{"pstxssp",	  P8LS|OP(47),	       P_D_MASK,	POWERXX, 0,	{VS, D34, PRA0, PCREL}},

>+{"plfs",	  PMLS|OP(48),	       P_D_MASK,	POWERXX, 0,	{FRT, D34, PRA0, PCREL}},

>+{"plxv",	  P8LS|OP(50),	       P_D_MASK&~OP(1),	POWERXX, 0,	{XTOP, D34, PRA0, PCREL}},

>+{"plfd",	  PMLS|OP(50),	       P_D_MASK,	POWERXX, 0,	{FRT, D34, PRA0, PCREL}},

>+{"pstfs",	  PMLS|OP(52),	       P_D_MASK,	POWERXX, 0,	{FRS, D34, PRA0, PCREL}},

>+{"pstxv",	  P8LS|OP(54),	       P_D_MASK&~OP(1),	POWERXX, 0,	{XTOP, D34, PRA0, PCREL}},

>+{"pstfd",	  PMLS|OP(54),	       P_D_MASK,	POWERXX, 0,	{FRS, D34, PRA0, PCREL}},

>+{"plq",		  P8LS|OP(56),	       P_D_MASK,	POWERXX, 0,	{RTQ, D34, PRAQ, PCREL}},

>+{"pld",		  P8LS|OP(57),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},

>+{"pstq",	  P8LS|OP(60),	       P_D_MASK,	POWERXX, 0,	{RSQ, D34, PRA0, PCREL}},

>+{"pstd",	  P8LS|OP(61),	       P_D_MASK,	POWERXX, 0,	{RS, D34, PRA0, PCREL}},

>};
Alan Modra June 20, 2019, 1:17 p.m. | #2
On Thu, Jun 20, 2019 at 06:04:43AM -0600, Jan Beulich wrote:
> >>> Alan Modra <amodra@gmail.com> 05/24/19 3:34 AM >>>

> >@@ -7815,6 +7969,32 @@ const unsigned int powerpc_num_opcodes =

>  >

> >const struct powerpc_opcode prefix_opcodes[] = {

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

> >+{"pli",		  PMLS|OP(14),	       P_DRAPCREL_MASK,	POWERXX, 0,	{RT, SI34}},

> >+{"paddi",	  PMLS|OP(14),	       P_D_MASK,	POWERXX, 0,	{RT, RA0, SI34, PCREL0}},

> >+{"psubi",	  PMLS|OP(14),	       P_D_MASK,	POWERXX, 0,	{RT, RA0, NSI34, PCREL0}},

> >+{"pla",		  PMLS|OP(14),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},

> >+{"plwz",	  PMLS|OP(32),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},

> >+{"plbz",	  PMLS|OP(34),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},

> >+{"pstw",	  PMLS|OP(36),	       P_D_MASK,	POWERXX, 0,	{RS, D34, PRA0, PCREL}},

> >+{"pstb",	  PMLS|OP(38),	       P_D_MASK,	POWERXX, 0,	{RS, D34, PRA0, PCREL}},

> >+{"plhz",	  PMLS|OP(40),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},

> >+{"plwa",	  P8LS|OP(41),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},

> 

> Comparing with the neighboring ones - isn't this supposed to use PMLS?


No.  The PMLS forms use the same opcode in the suffix word.  plwa
doesn't share the lwa encoding, and doesn't have the lwa restriction
of the offset being a multiple of 4.

-- 
Alan Modra
Australia Development Lab, IBM

Patch

diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 4abb5b8a31..4026c72293 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -1987,8 +1987,10 @@  ppc_insert_operand (uint64_t insn,
 	 hand but only up to 32 bits.  This shouldn't really be valid,
 	 but, to permit this code to assemble on a 64-bit host, we
 	 sign extend the 32-bit value to 64 bits if so doing makes the
-	 value valid.  */
+	 value valid.  We only do this for operands that are 32-bits or
+	 smaller.  */
       if (val > max
+	  && (operand->bitm & ~0xffffffffULL) == 0
 	  && (val - (1LL << 32)) >= min
 	  && (val - (1LL << 32)) <= max
 	  && ((val - (1LL << 32)) & (right - 1)) == 0)
@@ -1997,6 +1999,7 @@  ppc_insert_operand (uint64_t insn,
       /* Similarly, people write expressions like ~(1<<15), and expect
 	 this to be OK for a 32-bit unsigned value.  */
       else if (val < min
+	       && (operand->bitm & ~0xffffffffULL) == 0
 	       && (val + (1LL << 32)) >= min
 	       && (val + (1LL << 32)) <= max
 	       && ((val + (1LL << 32)) & (right - 1)) == 0)
diff --git a/gas/messages.c b/gas/messages.c
index 95471a6bef..b7d82f595d 100644
--- a/gas/messages.c
+++ b/gas/messages.c
@@ -397,13 +397,12 @@  as_internal_value_out_of_range (const char *prefix,
 	abort ();
 
       /* xgettext:c-format  */
-      err = _("%s out of domain (%d is not a multiple of %d)");
+      err = _("%s out of domain (%" BFD_VMA_FMT "d is not a multiple of %" \
+	      BFD_VMA_FMT "d)");
       if (bad)
-	as_bad_where (file, line, err,
-		      prefix, (int) val, (int) right);
+	as_bad_where (file, line, err, prefix, val, right);
       else
-	as_warn_where (file, line, err,
-		       prefix, (int) val, (int) right);
+	as_warn_where (file, line, err, prefix, val, right);
       return;
     }
 
@@ -415,14 +414,13 @@  as_internal_value_out_of_range (const char *prefix,
       && max > HEX_MIN_THRESHOLD)
     {
       /* xgettext:c-format  */
-      err = _("%s out of range (%d is not between %d and %d)");
+      err = _("%s out of range (%" BFD_VMA_FMT "d is not between %" \
+	      BFD_VMA_FMT "d and %" BFD_VMA_FMT "d)");
 
       if (bad)
-	as_bad_where (file, line, err,
-		      prefix, (int) val, (int) min, (int) max);
+	as_bad_where (file, line, err, prefix, val, min, max);
       else
-	as_warn_where (file, line, err,
-		       prefix, (int) val, (int) min, (int) max);
+	as_warn_where (file, line, err, prefix, val, min, max);
     }
   else
     {
diff --git a/gas/testsuite/gas/ppc/ppc.exp b/gas/testsuite/gas/ppc/ppc.exp
index 6be042bf26..aa199d5e85 100644
--- a/gas/testsuite/gas/ppc/ppc.exp
+++ b/gas/testsuite/gas/ppc/ppc.exp
@@ -115,3 +115,4 @@  run_dump_test "vsx3"
 run_dump_test "htm"
 run_dump_test "titan"
 run_dump_test "prefix-align"
+run_dump_test "prefix-pcrel"
diff --git a/gas/testsuite/gas/ppc/prefix-pcrel.d b/gas/testsuite/gas/ppc/prefix-pcrel.d
new file mode 100644
index 0000000000..a0ca60fa54
--- /dev/null
+++ b/gas/testsuite/gas/ppc/prefix-pcrel.d
@@ -0,0 +1,235 @@ 
+#as: -mfuture
+#objdump: -dr -Mfuture
+#name: POWERXX pcrel tests
+
+.*
+
+
+Disassembly of section \.text:
+
+0+00 <prefix>:
+.*:	(06 00 00 00|00 00 00 06) 	paddi   r10,r9,0
+.*:	(39 49 00 00|00 00 49 39) 
+.*:	(06 00 00 00|00 00 00 06) 	paddi   r10,r9,0
+.*:	(39 49 00 00|00 00 49 39) 
+.*:	(06 00 00 00|00 00 00 06) 	paddi   r10,r9,0
+.*:	(39 49 00 00|00 00 49 39) 
+.*:	(06 03 ff ff|ff ff 03 06) 	paddi   r11,r9,-32769
+.*:	(39 69 7f ff|ff 7f 69 39) 
+.*:	(06 03 ff ff|ff ff 03 06) 	paddi   r11,r9,-32769
+.*:	(39 69 7f ff|ff 7f 69 39) 
+.*:	(06 03 ff ff|ff ff 03 06) 	paddi   r11,r9,-32769
+.*:	(39 69 7f ff|ff 7f 69 39) 
+.*:	(06 01 ff ff|ff ff 01 06) 	paddi   r12,r9,8589934591
+.*:	(39 89 ff ff|ff ff 89 39) 
+.*:	(06 01 ff ff|ff ff 01 06) 	paddi   r12,r9,8589934591
+.*:	(39 89 ff ff|ff ff 89 39) 
+.*:	(06 01 ff ff|ff ff 01 06) 	paddi   r12,r9,8589934591
+.*:	(39 89 ff ff|ff ff 89 39) 
+.*:	(06 01 ff ff|ff ff 01 06) 	paddi   r12,r9,8589934591
+.*:	(39 89 ff ff|ff ff 89 39) 
+.*:	(06 01 ff ff|ff ff 01 06) 	paddi   r12,r9,8589934591
+.*:	(39 89 ff ff|ff ff 89 39) 
+.*:	(06 02 00 00|00 00 02 06) 	paddi   r13,r9,-8589934592
+.*:	(39 a9 00 00|00 00 a9 39) 
+.*:	(06 02 00 00|00 00 02 06) 	paddi   r13,r9,-8589934592
+.*:	(39 a9 00 00|00 00 a9 39) 
+.*:	(06 02 00 00|00 00 02 06) 	paddi   r13,r9,-8589934592
+.*:	(39 a9 00 00|00 00 a9 39) 
+.*:	(06 02 00 00|00 00 02 06) 	paddi   r13,r9,-8589934592
+.*:	(39 a9 00 00|00 00 a9 39) 
+.*:	(06 02 00 00|00 00 02 06) 	paddi   r13,r9,-8589934592
+.*:	(39 a9 00 00|00 00 a9 39) 
+.*:	(06 10 00 00|00 00 10 06) 	pla     r14,0
+.*:	(39 c0 00 00|00 00 c0 39) 
+.*:	(06 10 00 00|00 00 10 06) 	pla     r14,0
+.*:	(39 c0 00 00|00 00 c0 39) 
+.*:	(06 13 ff ff|ff ff 13 06) 	pla     r15,-32769
+.*:	(39 e0 7f ff|ff 7f e0 39) 
+.*:	(06 13 ff ff|ff ff 13 06) 	pla     r15,-32769
+.*:	(39 e0 7f ff|ff 7f e0 39) 
+.*:	(06 13 ff ff|ff ff 13 06) 	pla     r15,-32769
+.*:	(39 e0 7f ff|ff 7f e0 39) 
+.*:	(06 11 ff ff|ff ff 11 06) 	pla     r16,8589934591
+.*:	(3a 00 ff ff|ff ff 00 3a) 
+.*:	(06 11 ff ff|ff ff 11 06) 	pla     r16,8589934591
+.*:	(3a 00 ff ff|ff ff 00 3a) 
+.*:	(06 11 ff ff|ff ff 11 06) 	pla     r16,8589934591
+.*:	(3a 00 ff ff|ff ff 00 3a) 
+.*:	(06 12 00 00|00 00 12 06) 	pla     r17,-8589934592
+.*:	(3a 20 00 00|00 00 20 3a) 
+.*:	(06 12 00 00|00 00 12 06) 	pla     r17,-8589934592
+.*:	(3a 20 00 00|00 00 20 3a) 
+.*:	(06 12 00 00|00 00 12 06) 	pla     r17,-8589934592
+.*:	(3a 20 00 00|00 00 20 3a) 
+.*:	(06 00 00 00|00 00 00 06) 	pli     r20,13
+.*:	(3a 80 00 0d|0d 00 80 3a) 
+.*:	(06 00 00 00|00 00 00 06) 	pli     r20,13
+.*:	(3a 80 00 0d|0d 00 80 3a) 
+.*:	(06 00 00 00|00 00 00 06) 	pli     r20,13
+.*:	(3a 80 00 0d|0d 00 80 3a) 
+.*:	(06 00 00 00|00 00 00 06) 	pli     r20,13
+.*:	(3a 80 00 0d|0d 00 80 3a) 
+.*:	(06 03 ff ff|ff ff 03 06) 	pli     r21,-32769
+.*:	(3a a0 7f ff|ff 7f a0 3a) 
+.*:	(06 03 ff ff|ff ff 03 06) 	pli     r21,-32769
+.*:	(3a a0 7f ff|ff 7f a0 3a) 
+.*:	(06 03 ff ff|ff ff 03 06) 	pli     r21,-32769
+.*:	(3a a0 7f ff|ff 7f a0 3a) 
+.*:	(06 01 ff ff|ff ff 01 06) 	pli     r22,8589934591
+.*:	(3a c0 ff ff|ff ff c0 3a) 
+.*:	(06 01 ff ff|ff ff 01 06) 	pli     r22,8589934591
+.*:	(3a c0 ff ff|ff ff c0 3a) 
+.*:	(06 01 ff ff|ff ff 01 06) 	pli     r22,8589934591
+.*:	(3a c0 ff ff|ff ff c0 3a) 
+.*:	(06 01 ff ff|ff ff 01 06) 	pli     r22,8589934591
+.*:	(3a c0 ff ff|ff ff c0 3a) 
+.*:	(06 01 ff ff|ff ff 01 06) 	pli     r22,8589934591
+.*:	(3a c0 ff ff|ff ff c0 3a) 
+.*:	(06 01 ff ff|ff ff 01 06) 	pli     r22,8589934591
+.*:	(3a c0 ff ff|ff ff c0 3a) 
+.*:	(06 02 00 00|00 00 02 06) 	pli     r23,-8589934592
+.*:	(3a e0 00 00|00 00 e0 3a) 
+.*:	(06 02 00 00|00 00 02 06) 	pli     r23,-8589934592
+.*:	(3a e0 00 00|00 00 e0 3a) 
+.*:	(06 02 00 00|00 00 02 06) 	pli     r23,-8589934592
+.*:	(3a e0 00 00|00 00 e0 3a) 
+.*:	(06 02 00 00|00 00 02 06) 	pli     r23,-8589934592
+.*:	(3a e0 00 00|00 00 e0 3a) 
+.*:	(06 02 00 00|00 00 02 06) 	pli     r23,-8589934592
+.*:	(3a e0 00 00|00 00 e0 3a) 
+.*:	(06 02 00 00|00 00 02 06) 	pli     r23,-8589934592
+.*:	(3a e0 00 00|00 00 e0 3a) 
+.*:	(06 00 00 00|00 00 00 06) 	plbz    r3,0\(r1\)
+.*:	(88 61 00 00|00 00 61 88) 
+.*:	(06 00 00 00|00 00 00 06) 	plbz    r3,0\(r1\)
+.*:	(88 61 00 00|00 00 61 88) 
+.*:	(06 03 ff ff|ff ff 03 06) 	plbz    r3,-32769\(r1\)
+.*:	(88 61 7f ff|ff 7f 61 88) 
+.*:	(06 03 ff ff|ff ff 03 06) 	plbz    r3,-32769\(r1\)
+.*:	(88 61 7f ff|ff 7f 61 88) 
+.*:	(06 01 ff ff|ff ff 01 06) 	plbz    r3,8589934591\(r1\)
+.*:	(88 61 ff ff|ff ff 61 88) 
+.*:	(06 01 ff ff|ff ff 01 06) 	plbz    r3,8589934591\(r1\)
+.*:	(88 61 ff ff|ff ff 61 88) 
+.*:	(06 02 00 00|00 00 02 06) 	plbz    r3,-8589934592\(r1\)
+.*:	(88 61 00 00|00 00 61 88) 
+.*:	(06 02 00 00|00 00 02 06) 	plbz    r3,-8589934592\(r1\)
+.*:	(88 61 00 00|00 00 61 88) 
+.*:	(06 00 00 00|00 00 00 06) 	plbz    r3,0\(0\)
+.*:	(88 60 00 00|00 00 60 88) 
+.*:	(06 10 00 00|00 00 10 06) 	plbz    r4,0
+.*:	(88 80 00 00|00 00 80 88) 
+.*:	(06 10 00 00|00 00 10 06) 	plbz    r4,0
+.*:	(88 80 00 00|00 00 80 88) 
+.*:	(06 03 ff ff|ff ff 03 06) 	plbz    r3,-32769\(0\)
+.*:	(88 60 7f ff|ff 7f 60 88) 
+.*:	(06 13 ff ff|ff ff 13 06) 	plbz    r4,-32769
+.*:	(88 80 7f ff|ff 7f 80 88) 
+.*:	(06 13 ff ff|ff ff 13 06) 	plbz    r4,-32769
+.*:	(88 80 7f ff|ff 7f 80 88) 
+.*:	(06 01 ff ff|ff ff 01 06) 	plbz    r3,8589934591\(0\)
+.*:	(88 60 ff ff|ff ff 60 88) 
+.*:	(06 11 ff ff|ff ff 11 06) 	plbz    r4,8589934591
+.*:	(88 80 ff ff|ff ff 80 88) 
+.*:	(06 11 ff ff|ff ff 11 06) 	plbz    r4,8589934591
+.*:	(88 80 ff ff|ff ff 80 88) 
+.*:	(06 02 00 00|00 00 02 06) 	plbz    r3,-8589934592\(0\)
+.*:	(88 60 00 00|00 00 60 88) 
+.*:	(06 12 00 00|00 00 12 06) 	plbz    r4,-8589934592
+.*:	(88 80 00 00|00 00 80 88) 
+.*:	(06 12 00 00|00 00 12 06) 	plbz    r4,-8589934592
+.*:	(88 80 00 00|00 00 80 88) 
+.*:	(06 00 00 00|00 00 00 06) 	plhz    r5,4\(r10\)
+.*:	(a0 aa 00 04|04 00 aa a0) 
+.*:	(06 10 00 00|00 00 10 06) 	plhz    r5,4
+.*:	(a0 a0 00 04|04 00 a0 a0) 
+.*:	(06 00 00 00|00 00 00 06) 	plha    r6,8\(r10\)
+.*:	(a8 ca 00 08|08 00 ca a8) 
+.*:	(06 10 00 00|00 00 10 06) 	plha    r6,8
+.*:	(a8 c0 00 08|08 00 c0 a8) 
+.*:	(06 00 00 00|00 00 00 06) 	plwz    r7,12\(r10\)
+.*:	(80 ea 00 0c|0c 00 ea 80) 
+.*:	(06 10 00 00|00 00 10 06) 	plwz    r7,12
+.*:	(80 e0 00 0c|0c 00 e0 80) 
+.*:	(04 00 00 00|00 00 00 04) 	plwa    r8,16\(r10\)
+.*:	(a5 0a 00 10|10 00 0a a5) 
+.*:	(04 10 00 00|00 00 10 04) 	plwa    r8,16
+.*:	(a5 00 00 10|10 00 00 a5) 
+.*:	(04 00 00 00|00 00 00 04) 	pld     r9,20\(r10\)
+.*:	(e5 2a 00 14|14 00 2a e5) 
+.*:	(04 10 00 00|00 00 10 04) 	pld     r9,20
+.*:	(e5 20 00 14|14 00 20 e5) 
+.*:	(06 00 00 00|00 00 00 06) 	plfs    f10,24\(r10\)
+.*:	(c1 4a 00 18|18 00 4a c1) 
+.*:	(06 10 00 00|00 00 10 06) 	plfs    f10,24
+.*:	(c1 40 00 18|18 00 40 c1) 
+.*:	(06 00 00 00|00 00 00 06) 	plfd    f11,28\(r10\)
+.*:	(c9 6a 00 1c|1c 00 6a c9) 
+.*:	(06 10 00 00|00 00 10 06) 	plfd    f11,28
+.*:	(c9 60 00 1c|1c 00 60 c9) 
+.*:	(04 00 00 00|00 00 00 04) 	plxsd   v13,36\(r10\)
+.*:	(a9 aa 00 24|24 00 aa a9) 
+.*:	(04 10 00 00|00 00 10 04) 	plxsd   v13,36
+.*:	(a9 a0 00 24|24 00 a0 a9) 
+.*:	(04 00 00 00|00 00 00 04) 	plxssp  v14,40\(r10\)
+.*:	(ad ca 00 28|28 00 ca ad) 
+.*:	(04 10 00 00|00 00 10 04) 	plxssp  v14,40
+.*:	(ad c0 00 28|28 00 c0 ad) 
+.*:	(04 00 00 00|00 00 00 04) 	plq     r16,48\(r10\)
+.*:	(e2 0a 00 30|30 00 0a e2) 
+.*:	(04 10 00 00|00 00 10 04) 	plq     r16,48
+.*:	(e2 00 00 30|30 00 00 e2) 
+.*:	(04 00 00 00|00 00 00 04) 	plxv    vs17,64\(r10\)
+.*:	(ca 2a 00 40|40 00 2a ca) 
+.*:	(04 10 00 00|00 00 10 04) 	plxv    vs17,64
+.*:	(ca 20 00 40|40 00 20 ca) 
+.*:	(04 00 00 00|00 00 00 04) 	plxv    vs34,64\(r10\)
+.*:	(cc 4a 00 40|40 00 4a cc) 
+.*:	(04 10 00 00|00 00 10 04) 	plxv    vs34,64
+.*:	(cc 40 00 40|40 00 40 cc) 
+.*:	(06 00 00 00|00 00 00 06) 	pstb    r3,52\(r11\)
+.*:	(98 6b 00 34|34 00 6b 98) 
+.*:	(06 10 00 00|00 00 10 06) 	pstb    r3,52
+.*:	(98 60 00 34|34 00 60 98) 
+.*:	(06 00 00 00|00 00 00 06) 	psth    r4,56\(r11\)
+.*:	(b0 8b 00 38|38 00 8b b0) 
+.*:	(06 10 00 00|00 00 10 06) 	psth    r4,56
+.*:	(b0 80 00 38|38 00 80 b0) 
+.*:	(06 00 00 00|00 00 00 06) 	pstw    r5,60\(r11\)
+.*:	(90 ab 00 3c|3c 00 ab 90) 
+.*:	(06 10 00 00|00 00 10 06) 	pstw    r5,60
+.*:	(90 a0 00 3c|3c 00 a0 90) 
+.*:	(06 00 00 00|00 00 00 06) 	pstfs   f6,64\(r11\)
+.*:	(d0 cb 00 40|40 00 cb d0) 
+.*:	(06 10 00 00|00 00 10 06) 	pstfs   f6,64
+.*:	(d0 c0 00 40|40 00 c0 d0) 
+.*:	(06 00 00 00|00 00 00 06) 	pstfd   f7,68\(r11\)
+.*:	(d8 eb 00 44|44 00 eb d8) 
+.*:	(06 10 00 00|00 00 10 06) 	pstfd   f7,68
+.*:	(d8 e0 00 44|44 00 e0 d8) 
+.*:	(04 00 00 00|00 00 00 04) 	pstxsd  v9,76\(r11\)
+.*:	(b9 2b 00 4c|4c 00 2b b9) 
+.*:	(04 10 00 00|00 00 10 04) 	pstxsd  v9,76
+.*:	(b9 20 00 4c|4c 00 20 b9) 
+.*:	(04 00 00 00|00 00 00 04) 	pstxssp v10,80\(r11\)
+.*:	(bd 4b 00 50|50 00 4b bd) 
+.*:	(04 10 00 00|00 00 10 04) 	pstxssp v10,80
+.*:	(bd 40 00 50|50 00 40 bd) 
+.*:	(04 00 00 00|00 00 00 04) 	pstd    r11,84\(r11\)
+.*:	(f5 6b 00 54|54 00 6b f5) 
+.*:	(04 10 00 00|00 00 10 04) 	pstd    r11,84
+.*:	(f5 60 00 54|54 00 60 f5) 
+.*:	(04 00 00 00|00 00 00 04) 	pstq    r12,88\(r11\)
+.*:	(f1 8b 00 58|58 00 8b f1) 
+.*:	(04 10 00 00|00 00 10 04) 	pstq    r12,88
+.*:	(f1 80 00 58|58 00 80 f1) 
+.*:	(04 00 00 00|00 00 00 04) 	pstxv   vs13,96\(r11\)
+.*:	(d9 ab 00 60|60 00 ab d9) 
+.*:	(04 10 00 00|00 00 10 04) 	pstxv   vs13,96
+.*:	(d9 a0 00 60|60 00 a0 d9) 
+.*:	(04 00 00 00|00 00 00 04) 	pstxv   vs63,96\(r11\)
+.*:	(df eb 00 60|60 00 eb df) 
+.*:	(04 10 00 00|00 00 10 04) 	pstxv   vs63,96
+.*:	(df e0 00 60|60 00 e0 df) 
+#pass
diff --git a/gas/testsuite/gas/ppc/prefix-pcrel.s b/gas/testsuite/gas/ppc/prefix-pcrel.s
new file mode 100644
index 0000000000..c3831d8a2c
--- /dev/null
+++ b/gas/testsuite/gas/ppc/prefix-pcrel.s
@@ -0,0 +1,121 @@ 
+	.text
+prefix:
+	# The following should all disassemble to: paddi rX,rY,disp
+	pla	10,0(9)
+	paddi	10,9,0
+	paddi	10,9,0,0
+	pla	11,~(1<<15)(9)
+	paddi	11,9,~(1<<15)
+	paddi	11,9,~(1<<15),0
+	pla	12,8589934591(9)
+	psubi	12,9,-8589934591
+	psubi	12,9,-8589934591,0
+	paddi	12,9,8589934591
+	paddi	12,9,8589934591,0
+	pla	13,-8589934592(9)
+	psubi	13,9,8589934592
+	psubi	13,9,8589934592,0
+	paddi	13,9,-8589934592
+	paddi	13,9,-8589934592,0
+
+	# The following should all disassemble to: pla rX,disp
+	pla	14,0
+	paddi	14,0,0,1
+	pla	15,~(1<<15)
+	psubi	15,0,-(~(1<<15)),1
+	paddi	15,0,~(1<<15),1
+	pla	16,8589934591
+	psubi	16,0,-8589934591,1
+	paddi	16,0,8589934591,1
+	pla	17,-8589934592
+	psubi	17,0,8589934592,1
+	paddi	17,0,-8589934592,1
+
+	# The following should all disassemble to: pli rX,immed
+	pli	20,13
+	pla	20,13(0)
+	psubi	20,0,-13
+	paddi	20,0,13
+	pli	21,~(1<<15)
+	pla	21,~(1<<15)(0)
+	paddi	21,0,~(1<<15)
+	pli	22,8589934591
+	pla	22,8589934591(0)
+	psubi	22,0,-8589934591
+	psubi	22,0,-8589934591,0
+	paddi	22,0,8589934591
+	paddi	22,0,8589934591,0
+	pli	23,-8589934592
+	pla	23,-8589934592(0)
+	psubi	23,0,8589934592
+	psubi	23,0,8589934592,0
+	paddi	23,0,-8589934592
+	paddi	23,0,-8589934592,0
+
+	# Tests of prefix loads and stores
+	plbz	3,0(1)
+	plbz	3,0(1),0
+	plbz	3,~(1<<15)(1)
+	plbz	3,~(1<<15)(1),0
+	plbz	3,8589934591(1)
+	plbz	3,8589934591(1),0
+	plbz	3,-8589934592(1)
+	plbz	3,-8589934592(1),0
+	plbz	3,0(0)
+	plbz	4,0(0),1
+	plbz	4,0
+	plbz	3,~(1<<15)(0)
+	plbz	4,~(1<<15)(0),1
+	plbz	4,~(1<<15)
+	plbz	3,8589934591(0)
+	plbz	4,8589934591(0),1
+	plbz	4,8589934591
+	plbz	3,-8589934592(0)
+	plbz	4,-8589934592(0),1
+	plbz	4,-8589934592
+	plhz	5,4(10),0
+	plhz	5,4(0),1
+	plha	6,8(10),0
+	plha	6,8(0),1
+	plwz	7,12(10),0
+	plwz	7,12(0),1
+	plwa	8,16(10),0
+	plwa	8,16(0),1
+	pld	9,20(10),0
+	pld	9,20(0),1
+	plfs	10,24(10),0
+	plfs	10,24(0),1
+	plfd	11,28(10),0
+	plfd	11,28(0),1
+	plxsd	13,36(10),0
+	plxsd	13,36(0),1
+	plxssp	14,40(10),0
+	plxssp	14,40(0),1
+	plq	16,48(10),0
+	plq	16,48(0),1
+	plxv	17,64(10),0
+	plxv	17,64(0),1
+	plxv	34,64(10),0
+	plxv	34,64(0),1
+	pstb	3,52(11),0
+	pstb	3,52(0),1
+	psth	4,56(11),0
+	psth	4,56(0),1
+	pstw	5,60(11),0
+	pstw	5,60(0),1
+	pstfs	6,64(11),0
+	pstfs	6,64(0),1
+	pstfd	7,68(11),0
+	pstfd	7,68(0),1
+	pstxsd	9,76(11),0
+	pstxsd	9,76(0),1
+	pstxssp	10,80(11),0
+	pstxssp	10,80(0),1
+	pstd	11,84(11),0
+	pstd	11,84(0),1
+	pstq	12,88(11),0
+	pstq	12,88(0),1
+	pstxv	13,96(11),0
+	pstxv	13,96(0),1
+	pstxv	63,96(11),0
+	pstxv	63,96(0),1
diff --git a/opcodes/ppc-opc.c b/opcodes/ppc-opc.c
index 7dc2d775d9..aa7184230f 100644
--- a/opcodes/ppc-opc.c
+++ b/opcodes/ppc-opc.c
@@ -596,6 +596,106 @@  extract_dxdn (uint64_t insn,
   return -extract_dxd (insn, dialect, invalid);
 }
 
+/* The D field in a 64-bit D form prefix instruction when the field is split
+   into separate D0 and D1 fields.  */
+
+static uint64_t
+insert_d34 (uint64_t insn,
+	    int64_t value,
+	    ppc_cpu_t dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
+{
+  return insn | ((value & 0x3ffff0000ULL) << 16) | (value & 0xffff);
+}
+
+static int64_t
+extract_d34 (uint64_t insn,
+	     ppc_cpu_t dialect ATTRIBUTE_UNUSED,
+	     int *invalid ATTRIBUTE_UNUSED)
+{
+  int64_t mask = 1ULL << 33;
+  int64_t value = ((insn >> 16) & 0x3ffff0000ULL) | (insn & 0xffff);
+  value = (value ^ mask) - mask;
+  return value;
+}
+
+/* The NSI34 field in an 8-byte D form prefix instruction.  This is the same
+   as the SI34 field, only negated.  The extraction function always marks it
+   as invalid, since we never want to recognize an instruction which uses
+   a field of this type.  */
+
+static uint64_t
+insert_nsi34 (uint64_t insn,
+	      int64_t value,
+	      ppc_cpu_t dialect,
+	      const char **errmsg)
+{
+  return insert_d34 (insn, -value, dialect, errmsg);
+}
+
+static int64_t
+extract_nsi34 (uint64_t insn,
+	       ppc_cpu_t dialect,
+	       int *invalid)
+{
+  int64_t value = extract_d34 (insn, dialect, invalid);
+  *invalid = 1;
+  return -value;
+}
+
+/* The R field in an 8-byte prefix instruction when there are restrictions
+   between R's value and the RA value (ie, they cannot both be non zero).  */
+
+static uint64_t
+insert_pcrel (uint64_t insn,
+	      int64_t value,
+	      ppc_cpu_t dialect ATTRIBUTE_UNUSED,
+	      const char **errmsg)
+{
+  value &= 0x1;
+  int64_t ra = (insn >> 16) & 0x1f;
+  if (ra != 0 && value != 0)
+    *errmsg = _("invalid R operand");
+
+  return insn | (value << 52);
+}
+
+static int64_t
+extract_pcrel (uint64_t insn,
+	       ppc_cpu_t dialect ATTRIBUTE_UNUSED,
+	       int *invalid)
+{
+  /* If called with *invalid < 0 to return the value for missing
+     operands, *invalid will be the negative count of missing operands
+     including this one.  Return a default value of 1 if the PRA0/PRAQ
+     operand was also omitted (ie. *invalid is -2).  Return a default
+     value of 0 if the PRA0/PRAQ operand was not omitted
+     (ie. *invalid is -1).  */
+  if (*invalid < 0)
+    return ~ *invalid & 1;
+
+  int64_t ra = (insn >> 16) & 0x1f;
+  int64_t pcrel = (insn >> 52) & 0x1;
+  if (ra != 0 && pcrel != 0)
+    *invalid = 1;
+
+  return pcrel;
+}
+
+/* Variant of extract_pcrel that sets invalid for R bit set.  The idea
+   is to disassemble "paddi rt,0,offset,1" as "pla rt,offset".  */
+
+static int64_t
+extract_pcrel0 (uint64_t insn,
+		ppc_cpu_t dialect,
+		int *invalid)
+{
+  int64_t pcrel = extract_pcrel (insn, dialect, invalid);
+  if (pcrel)
+    *invalid = 1;
+  return pcrel;
+}
+
 /* FXM mask in mfcr and mtcrf instructions.  */
 
 static uint64_t
@@ -758,6 +858,7 @@  extract_esync (uint64_t insn,
 	       ppc_cpu_t dialect ATTRIBUTE_UNUSED,
 	       int *invalid)
 {
+  /* Missing optional operands have a value of zero.  */
   if (*invalid < 0)
     return 0;
 
@@ -1013,6 +1114,7 @@  extract_raq (uint64_t insn,
 	     ppc_cpu_t dialect ATTRIBUTE_UNUSED,
 	     int *invalid)
 {
+  /* Missing optional operands have a value of zero.  */
   if (*invalid < 0)
     return 0;
 
@@ -1338,6 +1440,7 @@  extract_tbr (uint64_t insn,
 	     ppc_cpu_t dialect ATTRIBUTE_UNUSED,
 	     int *invalid)
 {
+  /* Missing optional operands have a value of 268.  */
   if (*invalid < 0)
     return 268;
 
@@ -1810,6 +1913,7 @@  extract_sxl (uint64_t insn,
 	     ppc_cpu_t dialect ATTRIBUTE_UNUSED,
 	     int *invalid)
 {
+  /* Missing optional operands have a value of one.  */
   if (*invalid < 0)
     return 1;
   return (insn >> 11) & 0x1;
@@ -2039,9 +2143,26 @@  const struct powerpc_operand powerpc_operands[] =
   { 0xfffc, 0, NULL, NULL,
     PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DS },
 
+  /* The D field in an 8-byte D form prefix instruction.  This is a displacement
+     off a register, and implies that the next operand is a register in
+     parentheses.  */
+#define D34 DS + 1
+  { 0x3ffffffff, PPC_OPSHIFT_INV, insert_d34, extract_d34,
+    PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+
+  /* The SI field in an 8-byte D form prefix instruction.  */
+#define SI34 D34 + 1
+  { 0x3ffffffff, PPC_OPSHIFT_INV, insert_d34, extract_d34, PPC_OPERAND_SIGNED },
+
+  /* The NSI field in an 8-byte D form prefix instruction.  This is the
+     same as the SI34 field, only negated.  */
+#define NSI34 SI34 + 1
+  { 0x3ffffffff, PPC_OPSHIFT_INV, insert_nsi34, extract_nsi34,
+    PPC_OPERAND_NEGATIVE | PPC_OPERAND_SIGNED },
+
   /* The DUIS or BHRBE fields in a XFX form instruction, 10 bits
      unsigned imediate */
-#define DUIS DS + 1
+#define DUIS NSI34 + 1
 #define BHRBE DUIS
   { 0x3ff, 11, NULL, NULL, 0 },
 
@@ -2217,16 +2338,33 @@  const struct powerpc_operand powerpc_operands[] =
 #define RA0 RA + 1
   { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR_0 },
 
+  /* Similar to above, but optional.  */
+#define PRA0 RA0 + 1
+  { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR_0 | PPC_OPERAND_OPTIONAL },
+
   /* The RA field in the DQ form lq or an lswx instruction, which have
      special value restrictions.  */
-#define RAQ RA0 + 1
+#define RAQ PRA0 + 1
 #define RAX RAQ
   { 0x1f, 16, insert_raq, extract_raq, PPC_OPERAND_GPR_0 },
 
+  /* Similar to above, but optional.  */
+#define PRAQ RAQ + 1
+  { 0x1f, 16, insert_raq, extract_raq,
+    PPC_OPERAND_GPR_0 | PPC_OPERAND_OPTIONAL },
+
+  /* The R field in an 8-byte D, DS, DQ or X form prefix instruction.  */
+#define PCREL PRAQ + 1
+#define PCREL_MASK (1ULL << 52)
+  { 0x1, 52, insert_pcrel, extract_pcrel, PPC_OPERAND_OPTIONAL },
+
+#define PCREL0 PCREL + 1
+  { 0x1, 52, insert_pcrel, extract_pcrel0, PPC_OPERAND_OPTIONAL },
+
   /* The RA field in a D or X form instruction which is an updating
      load, which means that the RA field may not be zero and may not
      equal the RT field.  */
-#define RAL RAQ + 1
+#define RAL PCREL0 + 1
   { 0x1f, 16, insert_ral, extract_ral, PPC_OPERAND_GPR_0 },
 
   /* The RA field in an lmw instruction, which has special value
@@ -2651,8 +2789,12 @@  const struct powerpc_operand powerpc_operands[] =
 #define XTQ6 XSQ6
   { 0x3f, PPC_OPSHIFT_INV, insert_xtq6, extract_xtq6, PPC_OPERAND_VSR },
 
+  /* The XT field in a plxv instruction.  Runs into the OP field.  */
+#define XTOP XSQ6 + 1
+  { 0x3f, 21, NULL, NULL, PPC_OPERAND_VSR },
+
   /* The XA field in an XX3 form instruction.  This is split.  */
-#define XA6 XTQ6 + 1
+#define XA6 XTOP + 1
   { 0x3f, PPC_OPSHIFT_INV, insert_xa6, extract_xa6, PPC_OPERAND_VSR },
 
   /* The XB field in an XX2 or XX3 form instruction.  This is split.  */
@@ -2730,9 +2872,21 @@  const unsigned int num_powerpc_operands = (sizeof (powerpc_operands)
 #define SUFFIX_MASK ((1ULL << 32) - 1)
 #define PREFIX_MASK (SUFFIX_MASK << 32)
 
+/* Prefix insn, eight byte load/store form 8LS.  */
+#define P8LS (PREFIX_OP | PREFIX_FORM (0))
+
+/* Prefix insn, modified load/store form MLS.  */
+#define PMLS (PREFIX_OP | PREFIX_FORM (2))
+
 /* Prefix insn, modified register to register form MRR.  */
 #define PMRR (PREFIX_OP | PREFIX_FORM (3))
 
+/* An 8-byte D form prefix instruction.  */
+#define P_D_MASK (((-1ULL << 50) & ~PCREL_MASK) | OP_MASK)
+
+/* The same as P_D_MASK, but with the RA and PCREL fields specified.  */
+#define P_DRAPCREL_MASK (P_D_MASK | PCREL_MASK | RA_MASK)
+
 /* 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.  */
@@ -7815,6 +7969,32 @@  const unsigned int powerpc_num_opcodes =
 
 const struct powerpc_opcode prefix_opcodes[] = {
 {"pnop",	  PMRR,		       PREFIX_MASK,	POWERXX, 0,	{0}},
+{"pli",		  PMLS|OP(14),	       P_DRAPCREL_MASK,	POWERXX, 0,	{RT, SI34}},
+{"paddi",	  PMLS|OP(14),	       P_D_MASK,	POWERXX, 0,	{RT, RA0, SI34, PCREL0}},
+{"psubi",	  PMLS|OP(14),	       P_D_MASK,	POWERXX, 0,	{RT, RA0, NSI34, PCREL0}},
+{"pla",		  PMLS|OP(14),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},
+{"plwz",	  PMLS|OP(32),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},
+{"plbz",	  PMLS|OP(34),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},
+{"pstw",	  PMLS|OP(36),	       P_D_MASK,	POWERXX, 0,	{RS, D34, PRA0, PCREL}},
+{"pstb",	  PMLS|OP(38),	       P_D_MASK,	POWERXX, 0,	{RS, D34, PRA0, PCREL}},
+{"plhz",	  PMLS|OP(40),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},
+{"plwa",	  P8LS|OP(41),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},
+{"plxsd",	  P8LS|OP(42),	       P_D_MASK,	POWERXX, 0,	{VD, D34, PRA0, PCREL}},
+{"plha",	  PMLS|OP(42),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},
+{"plxssp",	  P8LS|OP(43),	       P_D_MASK,	POWERXX, 0,	{VD, D34, PRA0, PCREL}},
+{"psth",	  PMLS|OP(44),	       P_D_MASK,	POWERXX, 0,	{RS, D34, PRA0, PCREL}},
+{"pstxsd",	  P8LS|OP(46),	       P_D_MASK,	POWERXX, 0,	{VS, D34, PRA0, PCREL}},
+{"pstxssp",	  P8LS|OP(47),	       P_D_MASK,	POWERXX, 0,	{VS, D34, PRA0, PCREL}},
+{"plfs",	  PMLS|OP(48),	       P_D_MASK,	POWERXX, 0,	{FRT, D34, PRA0, PCREL}},
+{"plxv",	  P8LS|OP(50),	       P_D_MASK&~OP(1),	POWERXX, 0,	{XTOP, D34, PRA0, PCREL}},
+{"plfd",	  PMLS|OP(50),	       P_D_MASK,	POWERXX, 0,	{FRT, D34, PRA0, PCREL}},
+{"pstfs",	  PMLS|OP(52),	       P_D_MASK,	POWERXX, 0,	{FRS, D34, PRA0, PCREL}},
+{"pstxv",	  P8LS|OP(54),	       P_D_MASK&~OP(1),	POWERXX, 0,	{XTOP, D34, PRA0, PCREL}},
+{"pstfd",	  PMLS|OP(54),	       P_D_MASK,	POWERXX, 0,	{FRS, D34, PRA0, PCREL}},
+{"plq",		  P8LS|OP(56),	       P_D_MASK,	POWERXX, 0,	{RTQ, D34, PRAQ, PCREL}},
+{"pld",		  P8LS|OP(57),	       P_D_MASK,	POWERXX, 0,	{RT, D34, PRA0, PCREL}},
+{"pstq",	  P8LS|OP(60),	       P_D_MASK,	POWERXX, 0,	{RSQ, D34, PRA0, PCREL}},
+{"pstd",	  P8LS|OP(61),	       P_D_MASK,	POWERXX, 0,	{RS, D34, PRA0, PCREL}},
 };
 
 const unsigned int prefix_num_opcodes =