This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] MIPS/GAS: Accept negative MIPS16 constant %hi expansions
- From: "Maciej W. Rozycki" <macro at codesourcery dot com>
- To: <binutils at sourceware dot org>
- Cc: Richard Sandiford <rdsandiford at googlemail dot com>
- Date: Fri, 21 Sep 2012 22:45:00 +0100
- Subject: [PATCH] MIPS/GAS: Accept negative MIPS16 constant %hi expansions
Hi,
The change allows negative constant %hi expansions in the MIPS16 mode
letting code like:
.set mips16
.set foo, -32769
blah:
li $2, %hi(foo)
sll $2, 16
addiu $2, %lo(foo)
build successfully -- without the change below an "operand value out of
range for instruction" error is produced.
This is in spirit actually consistent with how we handle %hi in the
MIPS16 mode in general. Consider the piece above. If foo is an external
symbol instead and is only resolved by the linker and the whole program
uses 32-bit kernel addresses, then the final value of foo is in fact
negative and the linker will let it through and use the signed upper half
regardless. So why not to allow it in expressions that turn out to
evaluate to a constant at the assembly time as well?
Now as to the change itself -- the 'U' operand/reloc code is used for LI,
but it is also used for the CMPI instruction. The likelihood of someone
using %hi with CMPI (or any macros that use it in expansion) is low, but I
decided to play safe after all and replaced it with an extra operand code,
newly added for use exclusively by LI. The rest is then mechanical.
The change causes no regressions in MIPS testing and is covered along
with some other fixes posted today with the test case I am going to send
next. OK to apply?
BTW, we can probably get rid of BFD_RELOC_MIPS16_HI16 altogether -- any
code that refers to it is dead, such a reloc is never actually produced.
The corresponding non-MIPS16 BFD_RELOC_HI16 reloc is only used internally
by macros, in a few cases throughout where a LUI alone or a LUI/ORI pair
is used rather than LUI/ADDIU, mainly to save instructions for some
corner-case 64-bit immediates. If support for such macros is ever carried
over to the MIPS16 mode then the reloc can be reinstated. What do you
think?
Maciej
2012-09-21 Maciej W. Rozycki <macro@codesourcery.com>
include/opcode/
* mips.h: Document new MIPS16 "u" operand code.
opcodes/
* mips16-opc.c (mips16_opcodes): Replace 'U' with 'u' for "li".
* mips-dis.c (print_mips16_insn_arg) <'u'>: Add.
gas/
* tc-mips.c (mips16_ip) <BFD_RELOC_MIPS16_HI16_S>: Convert the
range accepted to unsigned for the 'u' reloc code.
<BFD_RELOC_MIPS16_HI16>: Likewise.
<'u'>: Add.
(mips16_macro_build) <'u'>: Add.
(mips16_immed_operands): Add entry for 'u'.
Maciej
binutils-gas-mips16-hi16-unsigned.diff
Index: binutils-fsf-trunk-quilt/gas/config/tc-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/config/tc-mips.c 2012-09-21 18:34:00.000000000 +0100
+++ binutils-fsf-trunk-quilt/gas/config/tc-mips.c 2012-09-21 20:22:41.541768316 +0100
@@ -5179,6 +5179,7 @@ mips16_macro_build (expressionS *ep, con
case '8':
case 'V':
case 'C':
+ case 'u':
case 'U':
case 'k':
case 'K':
@@ -13345,14 +13346,28 @@ mips16_ip (char *str, struct mips_cl_ins
{
valueT tmp;
+ /* As a special exception we convert the upper half
+ of properly sign-extended 32-bit values used as
+ the immediate argument to LI to a 16-bit unsigned
+ value that the instruction accepts to permit a
+ constant expansion of <expr> in code sequences like
+
+ li $reg,%hi(<expr>)
+ sll $reg,16
+ addiu $reg,%lo(<expr>)
+ */
switch (*offset_reloc)
{
case BFD_RELOC_MIPS16_HI16_S:
tmp = (imm_expr.X_add_number + 0x8000) >> 16;
+ if (*imm_reloc - BFD_RELOC_UNUSED == 'u')
+ tmp = (tmp + 0x8000) ^ 0x8000;
break;
case BFD_RELOC_MIPS16_HI16:
tmp = imm_expr.X_add_number >> 16;
+ if (*imm_reloc - BFD_RELOC_UNUSED == 'u')
+ tmp = (tmp + 0x8000) ^ 0x8000;
break;
case BFD_RELOC_MIPS16_LO16:
@@ -13544,6 +13559,7 @@ mips16_ip (char *str, struct mips_cl_ins
case 'j':
case 'V':
case 'C':
+ case 'u':
case 'U':
case 'k':
case 'K':
@@ -13948,6 +13964,7 @@ static const struct mips16_immed_operand
{ '8', 8, 16, 0, MIPS16OP_SH_IMM8, 1, 0, 0 },
{ 'V', 8, 16, 2, MIPS16OP_SH_IMM8, 1, 0, 0 },
{ 'C', 8, 16, 3, MIPS16OP_SH_IMM8, 1, 0, 0 },
+ { 'u', 8, 16, 0, MIPS16OP_SH_IMM8, 1, 1, 0 },
{ 'U', 8, 16, 0, MIPS16OP_SH_IMM8, 1, 1, 0 },
{ 'k', 8, 16, 0, MIPS16OP_SH_IMM8, 0, 0, 0 },
{ 'K', 8, 16, 3, MIPS16OP_SH_IMM8, 0, 0, 0 },
Index: binutils-fsf-trunk-quilt/include/opcode/mips.h
===================================================================
--- binutils-fsf-trunk-quilt.orig/include/opcode/mips.h 2012-09-16 01:23:54.000000000 +0100
+++ binutils-fsf-trunk-quilt/include/opcode/mips.h 2012-09-21 19:53:38.491027432 +0100
@@ -1348,6 +1348,7 @@ extern int bfd_mips_num_opcodes;
"8" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8)
"V" 8 bit unsigned immediate * 4 (MIPS16OP_*_IMM8)
"C" 8 bit unsigned immediate * 8 (MIPS16OP_*_IMM8)
+ "u" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8) (full 16 bit unsigned)
"U" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8) (full 16 bit unsigned)
"k" 8 bit signed immediate * 0 (MIPS16OP_*_IMM8)
"K" 8 bit signed immediate * 8 (MIPS16OP_*_IMM8)
Index: binutils-fsf-trunk-quilt/opcodes/mips-dis.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/opcodes/mips-dis.c 2012-09-16 01:23:54.000000000 +0100
+++ binutils-fsf-trunk-quilt/opcodes/mips-dis.c 2012-09-21 20:26:16.150857104 +0100
@@ -1606,6 +1606,7 @@ print_mips16_insn_arg (char type,
case '8':
case 'V':
case 'C':
+ case 'u':
case 'U':
case 'k':
case 'K':
@@ -1715,6 +1716,7 @@ print_mips16_insn_arg (char type,
info->insn_type = dis_dref;
info->data_size = 8;
break;
+ case 'u':
case 'U':
nbits = 8;
immed = GET_OP (l, IMM8);
Index: binutils-fsf-trunk-quilt/opcodes/mips16-opc.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/opcodes/mips16-opc.c 2012-07-04 12:07:38.000000000 +0100
+++ binutils-fsf-trunk-quilt/opcodes/mips16-opc.c 2012-09-21 19:52:41.270795454 +0100
@@ -187,7 +187,7 @@ const struct mips_opcode mips16_opcodes[
{"ld", "y,D(S)", 0xf800, 0xff00, WR_y|RD_SP, 0, I3 },
{"lh", "y,H(x)", 0x8800, 0xf800, WR_y|RD_x, 0, I1 },
{"lhu", "y,H(x)", 0xa800, 0xf800, WR_y|RD_x, 0, I1 },
-{"li", "x,U", 0x6800, 0xf800, WR_x, 0, I1 },
+{"li", "x,u", 0x6800, 0xf800, WR_x, 0, I1 },
{"lw", "y,W(x)", 0x9800, 0xf800, WR_y|RD_x, 0, I1 },
{"lw", "x,A", 0xb000, 0xf800, WR_x|RD_PC, 0, I1 },
{"lw", "x,V(P)", 0xb000, 0xf800, WR_x|RD_PC, 0, I1 },