This is the mail archive of the binutils@sourceware.org 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]

[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 },


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