This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Add some power4 instructions
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: binutils at sources dot redhat dot com
- Date: Tue, 10 Jun 2003 16:56:40 +0930
- Subject: 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