This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Add some power4 instructions


This adds three power4 instructions to gas.  The patch was originally
provided by Gary Hade, who went to a lot of bother implementing *_DQ
relocs corresponding to the existing R_PPC64_*_DS relocs.  This is
actually the "right" way to do things, but since Gary wrote the patch
we've had a whole lot of TLS relocs added.  These need _DQ forms in some
cases.  Rather than adding yet more relocs, switch cases, and checking
that doing so didn't break the tls code, I decided to dispense with
the new relocs and just special case the "lq" insn under the existing
DS relocs.

bfd/ChangeLog
	* elf64-ppc.c (ppc64_elf_relocate_section <*_DS>): Special case lq.

gas/ChangeLog
	* config/tc-ppc.c (md_assemble): Handle PPC_OPERAND_DQ.
	(md_apply_fix3): Special case lq insn.

gas/testsuite/ChangeLog
	* gas/ppc/test2elf64.{s,d}: New test.
	* gas/ppc/ppc.exp: Run new test.

include/opcode/ChangeLog
	* ppc.h (PPC_OPERAND_DQ): Define.

opcodes/ChangeLog
	* ppc-opc.c (DQ, RAQ, RSQ, RTQ): Define.
	(insert_dq, extract_dq, insert_raq, insert_rtq, insert_rsq): New.
	(powerpc_opcodes): Add "attn", "lq" and "stq".


Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.100
diff -u -p -r1.100 elf64-ppc.c
--- bfd/elf64-ppc.c	8 Jun 2003 14:06:38 -0000	1.100
+++ bfd/elf64-ppc.c	10 Jun 2003 05:39:15 -0000
@@ -7315,7 +7315,7 @@ ppc64_elf_relocate_section (output_bfd, 
       bfd_vma relocation;
       bfd_boolean unresolved_reloc;
       bfd_boolean warned;
-      long insn;
+      long insn, mask;
       struct ppc_stub_hash_entry *stub_entry;
       bfd_vma max_br_offset;
       bfd_vma from;
@@ -8406,12 +8406,23 @@ ppc64_elf_relocate_section (output_bfd, 
 	case R_PPC64_TPREL16_LO_DS:
 	case R_PPC64_DTPREL16_DS:
 	case R_PPC64_DTPREL16_LO_DS:
-	  if (((relocation + addend) & 3) != 0)
+	  insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
+	  mask = 3;
+	  /* If this reloc is against an lq insn, then the value must be
+	     a multiple of 16.  This is somewhat of a hack, but the
+	     "correct" way to do this by defining _DQ forms of all the
+	     _DS relocs bloats all reloc switches in this file.  It
+	     doesn't seem to make much sense to use any of these relocs
+	     in data, so testing the insn should be safe.  */
+	  if ((insn & (0x3f << 26)) == (56 << 26))
+	    mask = 15;
+	  if (((relocation + addend) & mask) != 0)
 	    {
 	      (*_bfd_error_handler)
-		(_("%s: error: relocation %s not a multiple of 4"),
+		(_("%s: error: relocation %s not a multiple of %d"),
 		 bfd_archive_filename (input_bfd),
-		 ppc64_elf_howto_table[(int) r_type]->name);
+		 ppc64_elf_howto_table[(int) r_type]->name,
+		 mask + 1);
 	      bfd_set_error (bfd_error_bad_value);
 	      ret = FALSE;
 	      continue;
Index: gas/config/tc-ppc.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-ppc.c,v
retrieving revision 1.71
diff -u -p -r1.71 tc-ppc.c
--- gas/config/tc-ppc.c	21 May 2003 12:07:55 -0000	1.71
+++ gas/config/tc-ppc.c	10 Jun 2003 05:39:33 -0000
@@ -2447,7 +2447,7 @@ md_assemble (str)
 	    }
 
 	  if (ppc_obj64
-	      && (operand->flags & PPC_OPERAND_DS) != 0)
+	      && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
 	    {
 	      switch (reloc)
 		{
@@ -5714,13 +5714,18 @@ md_apply_fix3 (fixP, valP, seg)
 	    abort ();
 	  {
 	    unsigned char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
-	    unsigned long val;
+	    long val, mask;
 
 	    if (target_big_endian)
-	      val = bfd_getb16 (where);
+	      val = bfd_getb32 (where - 2);
 	    else
-	      val = bfd_getl16 (where);
-	    val |= (value & 0xfffc);
+	      val = bfd_getl32 (where);
+	    mask = 0xfffc;
+	    /* lq insns reserve the four lsbs.  */
+	    if ((ppc_cpu & PPC_OPCODE_POWER4) != 0
+		&& (val & (0x3f << 26)) == (56 << 26))
+	      mask = 0xfff0;
+	    val |= value & mask;
 	    if (target_big_endian)
 	      bfd_putb16 ((bfd_vma) val, where);
 	    else
Index: gas/testsuite/gas/ppc/ppc.exp
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/ppc/ppc.exp,v
retrieving revision 1.8
diff -u -p -r1.8 ppc.exp
--- gas/testsuite/gas/ppc/ppc.exp	22 Aug 2002 05:23:43 -0000	1.8
+++ gas/testsuite/gas/ppc/ppc.exp	10 Jun 2003 05:39:34 -0000
@@ -10,6 +10,7 @@ if { [istarget powerpc64*-*-*] || [istar
     run_dump_test "astest64"
     run_dump_test "astest2_64"
     run_dump_test "test1elf64"
+    run_dump_test "test2elf64"
 } elseif { [istarget powerpc*-*aix*] } then {
     run_dump_test "test1xcoff32"
 } elseif { [istarget powerpc*-*-*bsd*] \
Index: gas/testsuite/gas/ppc/test2elf64.d
===================================================================
RCS file: gas/testsuite/gas/ppc/test2elf64.d
diff -N gas/testsuite/gas/ppc/test2elf64.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/ppc/test2elf64.d	10 Jun 2003 05:44:33 -0000
@@ -0,0 +1,101 @@
+#objdump: -Drx -Mpower4
+#as: -mpower4
+#name: PowerPC Test 2, 64 bit elf, power4 instructions
+
+.*: +file format elf64-powerpc
+.*
+architecture: powerpc:common64, flags 0x0+11:
+HAS_RELOC, HAS_SYMS
+start address 0x0+
+
+Sections:
+Idx Name +Size +VMA +LMA +File off +Algn
+ +0 \.text +0+68 +0+ +0+ +.*
+ +CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
+ +1 \.data +0+10 +0+ +0+ +.*
+ +CONTENTS, ALLOC, LOAD, DATA
+ +2 \.bss +0+ +0+ +0+ +.*
+ +ALLOC
+ +3 \.toc +0+30 +0+ +0+ +.*
+ +CONTENTS, ALLOC, LOAD, RELOC, DATA
+SYMBOL TABLE:
+0+ l +d +\.text	0+ 
+0+ l +d +\.data	0+ 
+0+ l +d +\.bss	0+ 
+0+ l +\.data	0+ dsym0
+0+8 l +\.data	0+ dsym1
+0+ l +d +\.toc	0+ 
+0+8 l +\.data	0+ usym0
+0+10 l +\.data	0+ usym1
+0+ +\*UND\*	0+ esym0
+0+ +\*UND\*	0+ esym1
+
+
+Disassembly of section \.text:
+
+0+ <\.text>:
+ +0:	e0 83 00 00 	lq	r4,0\(r3\)
+			2: R_PPC64_ADDR16_LO_DS	dsym0
+ +4:	e0 83 00 00 	lq	r4,0\(r3\)
+			6: R_PPC64_ADDR16_LO_DS	dsym1
+ +8:	e0 83 00 00 	lq	r4,0\(r3\)
+			a: R_PPC64_ADDR16_LO_DS	usym0
+ +c:	e0 83 00 00 	lq	r4,0\(r3\)
+			e: R_PPC64_ADDR16_LO_DS	usym1
+ +10:	e0 83 00 00 	lq	r4,0\(r3\)
+			12: R_PPC64_ADDR16_LO_DS	esym0
+ +14:	e0 83 00 00 	lq	r4,0\(r3\)
+			16: R_PPC64_ADDR16_LO_DS	esym1
+ +18:	e0 82 00 00 	lq	r4,0\(r2\)
+			1a: R_PPC64_TOC16_DS	\.toc
+ +1c:	e0 82 00 00 	lq	r4,0\(r2\)
+			1e: R_PPC64_TOC16_DS	\.toc\+0x8
+ +20:	e0 82 00 10 	lq	r4,16\(r2\)
+			22: R_PPC64_TOC16_DS	\.toc\+0x10
+ +24:	e0 82 00 10 	lq	r4,16\(r2\)
+			26: R_PPC64_TOC16_DS	\.toc\+0x18
+ +28:	e0 82 00 20 	lq	r4,32\(r2\)
+			2a: R_PPC64_TOC16_DS	\.toc\+0x20
+ +2c:	e0 82 00 20 	lq	r4,32\(r2\)
+			2e: R_PPC64_TOC16_DS	\.toc\+0x28
+ +30:	e0 c2 00 20 	lq	r6,32\(r2\)
+			32: R_PPC64_TOC16_LO_DS	\.toc\+0x28
+ +34:	e0 80 00 00 	lq	r4,0\(r0\)
+			36: R_PPC64_ADDR16_LO_DS	\.text
+ +38:	e0 c3 00 00 	lq	r6,0\(r3\)
+			3a: R_PPC64_GOT16_DS	dsym0
+ +3c:	e0 c3 00 00 	lq	r6,0\(r3\)
+			3e: R_PPC64_GOT16_LO_DS	dsym0
+ +40:	e0 c3 00 00 	lq	r6,0\(r3\)
+			42: R_PPC64_PLT16_LO_DS	dsym0
+ +44:	e0 c3 00 00 	lq	r6,0\(r3\)
+			46: R_PPC64_SECTOFF_DS	dsym1
+ +48:	e0 c3 00 00 	lq	r6,0\(r3\)
+			4a: R_PPC64_SECTOFF_LO_DS	dsym1
+ +4c:	e0 c4 00 10 	lq	r6,16\(r4\)
+ +50:	f8 c7 00 02 	stq	r6,0\(r7\)
+ +54:	f8 c7 00 12 	stq	r6,16\(r7\)
+ +58:	f8 c7 ff f2 	stq	r6,-16\(r7\)
+ +5c:	f8 c7 80 02 	stq	r6,-32768\(r7\)
+ +60:	f8 c7 7f f2 	stq	r6,32752\(r7\)
+ +64:	00 00 02 00 	attn
+Disassembly of section \.data:
+
+0+ <dsym0>:
+ +0:	00 00 00 00 	\.long 0x0
+ +4:	de ad be ef 	stfdu	f21,-16657\(r13\)
+
+0+8 <dsym1>:
+ +8:	00 00 00 00 	\.long 0x0
+ +c:	ca fe ba be 	lfd	f23,-17730\(r30\)
+
+Disassembly of section \.toc:
+
+0+ <\.toc>:
+	\.\.\.
+			0: R_PPC64_ADDR64	dsym0
+			8: R_PPC64_ADDR64	dsym1
+			10: R_PPC64_ADDR64	usym0
+			18: R_PPC64_ADDR64	usym1
+			20: R_PPC64_ADDR64	esym0
+			28: R_PPC64_ADDR64	esym1
Index: gas/testsuite/gas/ppc/test2elf64.s
===================================================================
RCS file: gas/testsuite/gas/ppc/test2elf64.s
diff -N gas/testsuite/gas/ppc/test2elf64.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/ppc/test2elf64.s	10 Jun 2003 05:44:33 -0000
@@ -0,0 +1,53 @@
+
+	.section	".data"
+dsym0:	.llong	0xdeadbeef
+dsym1:
+
+
+	.section	".toc"
+.L_tsym0:
+	.tc	ignored0[TC],dsym0
+.L_tsym1:
+	.tc	ignored1[TC],dsym1
+.L_tsym2:
+	.tc	ignored2[TC],usym0
+.L_tsym3:
+	.tc	ignored3[TC],usym1
+.L_tsym4:
+	.tc	ignored4[TC],esym0
+.L_tsym5:
+	.tc	ignored5[TC],esym1
+
+
+	.section	".text"
+	lq	4,dsym0@l(3)
+	lq	4,dsym1@l(3)
+	lq	4,usym0@l(3)
+	lq	4,usym1@l(3)
+	lq	4,esym0@l(3)
+	lq	4,esym1@l(3)
+	lq	4,.L_tsym0@toc(2)
+	lq	4,.L_tsym1@toc(2)
+	lq	4,.L_tsym2@toc(2)
+	lq	4,.L_tsym3@toc(2)
+	lq	4,.L_tsym4@toc(2)
+	lq	4,.L_tsym5@toc(2)
+	lq	6,.L_tsym5@toc@l(2)
+	lq	4,.text@l(0)	
+	lq	6,dsym0@got(3)
+	lq	6,dsym0@got@l(3)
+	lq	6,dsym0@plt@l(3)
+	lq	6,dsym1@sectoff(3)
+	lq	6,dsym1@sectoff@l(3)
+	lq	6,usym1-dsym0@l(4)
+	stq 6,	0(7)
+	stq 6,	16(7)
+	stq 6,	-16(7)
+	stq 6,	-32768(7)
+	stq 6,	32752(7)
+	attn
+
+	.section	".data"
+usym0:	.llong	0xcafebabe
+usym1:
+
Index: include/opcode/ppc.h
===================================================================
RCS file: /cvs/src/src/include/opcode/ppc.h,v
retrieving revision 1.13
diff -u -p -r1.13 ppc.h
--- include/opcode/ppc.h	19 Aug 2002 20:55:48 -0000	1.13
+++ include/opcode/ppc.h	10 Jun 2003 05:39:37 -0000
@@ -273,6 +273,9 @@ extern const struct powerpc_operand powe
 
 /* This operand is for the DS field in a DS form instruction.  */
 #define PPC_OPERAND_DS (020000)
+
+/* This operand is for the DQ field in a DQ form instruction.  */
+#define PPC_OPERAND_DQ (040000)
 
 /* The POWER and PowerPC assemblers use a few macros.  We keep them
    with the operands table for simplicity.  The macro table is an
Index: opcodes/ppc-opc.c
===================================================================
RCS file: /cvs/src/src/opcodes/ppc-opc.c,v
retrieving revision 1.49
diff -u -p -r1.49 ppc-opc.c
--- opcodes/ppc-opc.c	17 Mar 2003 11:43:30 -0000	1.49
+++ opcodes/ppc-opc.c	10 Jun 2003 05:39:53 -0000
@@ -68,6 +68,10 @@ static unsigned long insert_boe
   PARAMS ((unsigned long, long, int, const char **));
 static long extract_boe
   PARAMS ((unsigned long, int, int *));
+static unsigned long insert_dq
+  PARAMS ((unsigned long, long, int, const char **));
+static long extract_dq
+  PARAMS ((unsigned long, int, int *));
 static unsigned long insert_ds
   PARAMS ((unsigned long, long, int, const char **));
 static long extract_ds
@@ -104,12 +108,18 @@ static unsigned long insert_ral
   PARAMS ((unsigned long, long, int, const char **));
 static unsigned long insert_ram
   PARAMS ((unsigned long, long, int, const char **));
+static unsigned long insert_raq
+  PARAMS ((unsigned long, long, int, const char **));
 static unsigned long insert_ras
   PARAMS ((unsigned long, long, int, const char **));
 static unsigned long insert_rbs
   PARAMS ((unsigned long, long, int, const char **));
 static long extract_rbs
   PARAMS ((unsigned long, int, int *));
+static unsigned long insert_rsq
+  PARAMS ((unsigned long, long, int, const char **));
+static unsigned long insert_rtq
+  PARAMS ((unsigned long, long, int, const char **));
 static unsigned long insert_sh6
   PARAMS ((unsigned long, long, int, const char **));
 static long extract_sh6
@@ -279,9 +289,15 @@ const struct powerpc_operand powerpc_ope
 #define DES DE + 1
   { 14, 0, insert_des, extract_des, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
 
+  /* The DQ field in a DQ form instruction.  This is like D, but the
+     lower four bits are forced to zero. */
+#define DQ DES + 1
+  { 16, 0, insert_dq, extract_dq,
+      PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DQ },
+
   /* The DS field in a DS form instruction.  This is like D, but the
      lower two bits are forced to zero.  */
-#define DS DES + 1
+#define DS DQ + 1
   { 16, 0, insert_ds, extract_ds,
       PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DS },
 
@@ -389,15 +405,20 @@ const struct powerpc_operand powerpc_ope
   { 16, 0, insert_nsi, extract_nsi,
       PPC_OPERAND_NEGATIVE | PPC_OPERAND_SIGNED },
 
-  /* The RA field in an D, DS, X, XO, M, or MDS form instruction.  */
+  /* The RA field in an D, DS, DQ, X, XO, M, or MDS form instruction.  */
 #define RA NSI + 1
 #define RA_MASK (0x1f << 16)
   { 5, 16, 0, 0, PPC_OPERAND_GPR },
 
+  /* The RA field in the DQ form lq instruction, which has special 
+     value restrictions.  */
+#define RAQ RA + 1
+  { 5, 16, insert_raq, 0, PPC_OPERAND_GPR },
+
   /* 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 RA + 1
+#define RAL RAQ + 1
   { 5, 16, insert_ral, 0, PPC_OPERAND_GPR },
 
   /* The RA field in an lmw instruction, which has special value
@@ -430,8 +451,18 @@ const struct powerpc_operand powerpc_ope
 #define RT_MASK (0x1f << 21)
   { 5, 21, 0, 0, PPC_OPERAND_GPR },
 
+  /* The RS field of the DS form stq instruction, which has special 
+     value restrictions.  */
+#define RSQ RS + 1
+  { 5, 21, insert_rsq, 0, PPC_OPERAND_GPR },
+
+  /* The RT field of the DQ form lq instruction, which has special
+     value restrictions.  */
+#define RTQ RSQ + 1
+  { 5, 21, insert_rtq, 0, PPC_OPERAND_GPR },
+
   /* The SH field in an X or M form instruction.  */
-#define SH RS + 1
+#define SH RTQ + 1
 #define SH_MASK (0x1f << 11)
   { 5, 11, 0, 0, 0 },
 
@@ -870,6 +901,32 @@ extract_boe (insn, dialect, invalid)
   return value & 0x1e;
 }
 
+  /* The DQ field in a DQ form instruction.  This is like D, but the
+     lower four bits are forced to zero. */
+
+/*ARGSUSED*/
+static unsigned long
+insert_dq (insn, value, dialect, errmsg)
+     unsigned long insn;
+     long value;
+     int dialect ATTRIBUTE_UNUSED;
+     const char ** errmsg ATTRIBUTE_UNUSED;
+{
+  if ((value & 0xf) != 0 && errmsg != NULL)
+    *errmsg = _("offset not a multiple of 16");
+  return insn | (value & 0xfff0);
+}
+
+/*ARGSUSED*/
+static long
+extract_dq (insn, dialect, invalid)
+     unsigned long insn;
+     int dialect ATTRIBUTE_UNUSED;
+     int *invalid ATTRIBUTE_UNUSED;
+{
+  return ((insn & 0xfff0) ^ 0x8000) - 0x8000;
+}
+
 static unsigned long
 insert_ev2 (insn, value, dialect, errmsg)
      unsigned long insn;
@@ -1253,6 +1310,24 @@ insert_ram (insn, value, dialect, errmsg
   return insn | ((value & 0x1f) << 16);
 }
 
+  /* The RA field in the DQ form lq instruction, which has special 
+     value restrictions.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_raq (insn, value, dialect, errmsg)
+     unsigned long insn;
+     long value;
+     int dialect ATTRIBUTE_UNUSED;
+     const char **errmsg;
+{
+  long rtvalue = (insn & RT_MASK) >> 21;
+
+  if (value == rtvalue && errmsg != NULL)
+    *errmsg = _("source and target register operands must be different");
+  return insn | ((value & 0x1f) << 16);
+}
+
 /* The RA field in a D or X form instruction which is an updating
    store or an updating floating point load, which means that the RA
    field may not be zero.  */
@@ -1298,6 +1373,38 @@ extract_rbs (insn, dialect, invalid)
   return 0;
 }
 
+  /* The RT field of the DQ form lq instruction, which has special
+     value restrictions.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_rtq (insn, value, dialect, errmsg)
+     unsigned long insn;
+     long value;
+     int dialect ATTRIBUTE_UNUSED;
+     const char **errmsg;
+{
+  if ((value & 1) != 0 && errmsg != NULL)
+    *errmsg = _("target register operand must be even");
+  return insn | ((value & 0x1f) << 21);
+}
+
+  /* The RS field of the DS form stq instruction, which has special 
+     value restrictions.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_rsq (insn, value, dialect, errmsg)
+     unsigned long insn;
+     long value ATTRIBUTE_UNUSED;
+     int dialect ATTRIBUTE_UNUSED;
+     const char **errmsg;
+{
+  if ((value & 1) != 0 && errmsg != NULL)
+    *errmsg = _("source register operand must be even");
+  return insn | ((value & 0x1f) << 21);
+}
+
 /* The SH field in an MD form instruction.  This is split.  */
 
 /*ARGSUSED*/
@@ -1768,6 +1875,7 @@ extract_tbr (insn, dialect, invalid)
    sorted by major opcode.  */
 
 const struct powerpc_opcode powerpc_opcodes[] = {
+{ "attn",    X(0,256), X_MASK,		POWER4,		{ 0 } },
 { "tdlgti",  OPTO(2,TOLGT), OPTO_MASK,	PPC64,		{ RA, SI } },
 { "tdllti",  OPTO(2,TOLLT), OPTO_MASK,	PPC64,		{ RA, SI } },
 { "tdeqi",   OPTO(2,TOEQ), OPTO_MASK,	PPC64,		{ RA, SI } },
@@ -4335,6 +4443,8 @@ const struct powerpc_opcode powerpc_opco
 
 { "stfdu",   OP(55),	OP_MASK,	COM,		{ FRS, D, RAS } },
 
+{ "lq",      OP(56),	OP_MASK,	POWER4,		{ RTQ, DQ, RAQ } },
+
 { "lfq",     OP(56),	OP_MASK,	POWER2,		{ FRT, D, RA } },
 
 { "lfqu",    OP(57),	OP_MASK,	POWER2,		{ FRT, D, RA } },
@@ -4410,6 +4520,8 @@ const struct powerpc_opcode powerpc_opco
 { "std",     DSO(62,0),	DS_MASK,	PPC64,		{ RS, DS, RA } },
 
 { "stdu",    DSO(62,1),	DS_MASK,	PPC64,		{ RS, DS, RAS } },
+
+{ "stq",     DSO(62,2),	DS_MASK,	POWER4,		{ RSQ, DS, RA } },
 
 { "fcmpu",   X(63,0),	X_MASK|(3<<21),	COM,		{ BF, FRA, FRB } },
 

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]