diff mbox

RFC: A new MIPS64 ABI

Message ID 4D6301ED.7040509@caviumnetworks.com
State New
Headers show

Commit Message

David Daney Feb. 22, 2011, 12:23 a.m. UTC
CC list trimmed, and redirected to gcc-patches@

On 02/21/2011 11:45 AM, Richard Sandiford wrote:
> David Daney<ddaney@caviumnetworks.com>  writes:
>> Background:
>>
>> Current MIPS 32-bit ABIs (both o32 and n32) are restricted to 2GB of
>> user virtual memory space.  This is due the way MIPS32 memory space is
>> segmented.  Only the range from 0..2^31-1 is available.  Pointer
>> values are always sign extended.
>>
>> Because there are not already enough MIPS ABIs, I present the ...
>>
>> Proposal: A new ABI to support 4GB of address space with 32-bit
>> pointers.
>
> FWIW, I'd be happy to see this go into GCC.
>

Ok, here is the general idea:

Everything identical to n32, except Pmode == DImode and
POINTERS_EXTEND_UNSIGNED == true.

Here is a patch that allows me to generate plausible looking assembly
for trivial programs.

Modulo lines that are too long and other possible coding standard
violations, what do you think about this approach.

Notes:

o Only works for TARGET_EXPLICIT_RELOCS, but this could change with
   assembler support I suppose.

o -mno-shared doesn't improve code over -mshared

-------------8<------------
int foo;
void f(void);

int *bar(void)
{
   f();
   return &foo;
}

struct dd {
   int a;
   void *b;
};

void *baa(struct dd *i)
{
   return i->b;
}
-------------8<------------

Yields:

	.file	1 "n32test.c"
	.section .mdebug.abiNB32
	.previous
	.gnu_attribute 4, 1
	.abicalls
	.text
	.align	2
	.align	3
	.globl	bar
	.set	nomips16
	.ent	bar
	.type	bar, @function
bar:
	.frame	$sp,16,$31		# vars= 0, regs= 2/0, args= 0, gp= 0
	.mask	0x90000000,-8
	.fmask	0x00000000,0
	.set	noreorder
	.set	nomacro
	daddiu	$sp,$sp,-16
	sd	$28,0($sp)
	ori	$28,$0,%hi(__gnu_local_gp)
	dsll	$28,$28,16
	daddiu	$28,$28,%lo(__gnu_local_gp)
	lwu	$25,%call16(f)($28)
	sd	$31,8($sp)
	.reloc	1f,R_MIPS_JALR,f
1:	jalr	$25
	nop

	ld	$31,8($sp)
	lwu	$2,%got_disp(foo)($28)
	ld	$28,0($sp)
	j	$31
	daddiu	$sp,$sp,16

	.set	macro
	.set	reorder
	.end	bar
	.size	bar, .-bar
	.align	2
	.align	3
	.globl	baa
	.set	nomips16
	.ent	baa
	.type	baa, @function
baa:
	.frame	$sp,0,$31		# vars= 0, regs= 0/0, args= 0, gp= 0
	.mask	0x00000000,0
	.fmask	0x00000000,0
	.set	noreorder
	.set	nomacro
	j	$31
	lwu	$2,4($4)

	.set	macro
	.set	reorder
	.end	baa
	.size	baa, .-baa

	.comm	foo,4,4
	.ident	"GCC: (GNU) 4.6.0 20110218 (experimental) [trunk revision 170267]"

Comments

Richard Sandiford Feb. 22, 2011, 8:38 p.m. UTC | #1
David Daney <ddaney@caviumnetworks.com> writes:
> Modulo lines that are too long and other possible coding standard
> violations, what do you think about this approach.

Yeah, the approach looks good to me.  Nice to see the patch is so small.

Richard
Alexandre Oliva May 6, 2011, 7:01 a.m. UTC | #2
Reviewing some old e-mail...

On Feb 21, 2011, David Daney <ddaney@caviumnetworks.com> wrote:

> Everything identical to n32, except Pmode == DImode and
> POINTERS_EXTEND_UNSIGNED == true.

> Here is a patch that allows me to generate plausible looking assembly
> for trivial programs.

Neat!

Just one suggestion: instead of NB32 (what does that stand for?) how
about naming it u32?  It's shorter, clear (to me), and there's the fun
factor that the lower-case u looks like an upside-down n.
diff mbox

Patch

Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	(revision 170267)
+++ gcc/config/mips/mips.md	(working copy)
@@ -97,6 +97,8 @@  (define_c_enum "unspec" [
   UNSPEC_UPDATE_GOT_VERSION
 
   ;; Symbolic accesses.
+  UNSPEC_LA_EXTEND
+  UNSPEC_LA_EXTEND_LO
   UNSPEC_LOAD_CALL
   UNSPEC_LOAD_GOT
   UNSPEC_TLS_LDM
@@ -2813,8 +2815,33 @@  (define_insn "*<optab>_trunc<mode>_exts"
 
 (define_expand "zero_extendsidi2"
   [(set (match_operand:DI 0 "register_operand")
-        (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand")))]
-  "TARGET_64BIT")
+        (zero_extend:DI (match_operand:SI 1 "general_operand")))]
+  "TARGET_64BIT"
+{
+  if (immediate_operand (operands[1], SImode))
+    {
+      mips_expand_zero_extend_symbol (operands[0], operands[1]);
+      DONE;
+    }
+})
+
+(define_insn "zero_extendsidi_high_address"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+        (unspec:DI [(zero_extend:DI (match_operand:SI 1 "immediate_operand" "i"))] UNSPEC_LA_EXTEND))]
+  "TARGET_64BIT"
+  "ori\t%0,%.,%h1"
+  [(set_attr "move_type" "const")
+   (set_attr "mode" "DI")])
+
+(define_insn "zero_extendsidi_low_address"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+         (unspec:DI [(lo_sum:DI 
+                       (match_operand:DI 1 "register_operand" "d")
+                       (match_operand:SI 2 "immediate_operand" "i"))] UNSPEC_LA_EXTEND_LO))]
+  "TARGET_64BIT"
+  "daddiu\t%0,%1,%R2"
+  [(set_attr "move_type" "const")
+   (set_attr "mode" "DI")])
 
 (define_insn_and_split "*zero_extendsidi2"
   [(set (match_operand:DI 0 "register_operand" "=d,d")
@@ -3868,7 +3895,10 @@  (define_insn "load_got<mode>"
 		   (match_operand:P 2 "immediate_operand" "")]
 		  UNSPEC_LOAD_GOT))]
   ""
-  "<load>\t%0,%R2(%1)"
+  {if (TARGET_NB32)
+     return "lwu\t%0,%R2(%1)";
+   else
+     return "<load>\t%0,%R2(%1)"; }
   [(set_attr "got" "load")
    (set_attr "mode" "<MODE>")])
 
@@ -5929,7 +5959,10 @@  (define_insn "load_call<mode>"
 		   (match_operand:P 2 "immediate_operand" "")
 		   (reg:SI GOT_VERSION_REGNUM)] UNSPEC_LOAD_CALL))]
   "TARGET_USE_GOT"
-  "<load>\t%0,%R2(%1)"
+  {if (TARGET_NB32)
+     return "lwu\t%0,%R2(%1)";
+   else
+     return "<load>\t%0,%R2(%1)"; }
   [(set_attr "got" "load")
    (set_attr "mode" "<MODE>")])
 
Index: gcc/config/mips/mips-protos.h
===================================================================
--- gcc/config/mips/mips-protos.h	(revision 170267)
+++ gcc/config/mips/mips-protos.h	(working copy)
@@ -339,4 +339,6 @@  typedef rtx (*mulsidi3_gen_fn) (rtx, rtx
 extern mulsidi3_gen_fn mips_mulsidi3_gen_fn (enum rtx_code);
 #endif
 
+extern void mips_expand_zero_extend_symbol (rtx, rtx);
+
 #endif /* ! GCC_MIPS_PROTOS_H */
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	(revision 170267)
+++ gcc/config/mips/mips.c	(working copy)
@@ -2812,7 +2812,9 @@  mips_split_symbol (rtx temp, rtx addr, e
 		break;
 
 	      default:
-		high = gen_rtx_HIGH (Pmode, copy_rtx (addr));
+		high = gen_rtx_HIGH (ptr_mode, copy_rtx (addr));
+		if (GET_MODE (high) != Pmode)
+		  high = gen_rtx_ZERO_EXTEND (Pmode, high);
 		high = mips_force_temporary (temp, high);
 		*low_out = gen_rtx_LO_SUM (Pmode, high, addr);
 		break;
@@ -4743,6 +4745,7 @@  mips_get_arg_info (struct mips_arg_info 
       break;
 
     case ABI_N32:
+    case ABI_NB32:
     case ABI_64:
       /* Scalar, complex and vector floating-point types are passed in
 	 floating-point registers, as long as this is a named rather
@@ -8175,6 +8178,8 @@  mips_mdebug_abi_name (void)
       return "abiO64";
     case ABI_N32:
       return "abiN32";
+    case ABI_NB32:
+      return "abiNB32";
     case ABI_64:
       return "abi64";
     case ABI_EABI:
@@ -9998,12 +10003,17 @@  mips_emit_loadgp (void)
     case LOADGP_ABSOLUTE:
       if (mips_gnu_local_gp == NULL)
 	{
-	  mips_gnu_local_gp = gen_rtx_SYMBOL_REF (Pmode, "__gnu_local_gp");
+	  mips_gnu_local_gp = gen_rtx_SYMBOL_REF (ptr_mode, "__gnu_local_gp");
 	  SYMBOL_REF_FLAGS (mips_gnu_local_gp) |= SYMBOL_FLAG_LOCAL;
 	}
-      emit_insn (Pmode == SImode
-		 ? gen_loadgp_absolute_si (pic_reg, mips_gnu_local_gp)
-		 : gen_loadgp_absolute_di (pic_reg, mips_gnu_local_gp));
+      if (TARGET_NB32)
+	{
+	  emit_insn (gen_zero_extendsidi2 (pic_reg, mips_gnu_local_gp));
+	}
+      else
+	emit_insn (Pmode == SImode
+		   ? gen_loadgp_absolute_si (pic_reg, mips_gnu_local_gp)
+		   : gen_loadgp_absolute_di (pic_reg, mips_gnu_local_gp));
       break;
 
     case LOADGP_OLDABI:
@@ -11233,6 +11243,11 @@  mips_process_load_label (rtx target)
       mips_multi_add_insn ("addiu\t%@,%@,%%got_ofst(%0)", target, 0);
       break;
 
+    case ABI_NB32:
+      mips_multi_add_insn ("lwu\t%@,%%got_page(%0)(%+)", target, 0);
+      mips_multi_add_insn ("daddiu\t%@,%@,%%got_ofst(%0)", target, 0);
+      break;
+
     case ABI_64:
       mips_multi_add_insn ("ld\t%@,%%got_page(%0)(%+)", target, 0);
       mips_multi_add_insn ("daddiu\t%@,%@,%%got_ofst(%0)", target, 0);
@@ -15468,6 +15483,8 @@  mips_handle_option (size_t code, const c
 	mips_abi = ABI_O64;
       else if (strcmp (arg, "n32") == 0)
 	mips_abi = ABI_N32;
+      else if (strcmp (arg, "nb32") == 0)
+	mips_abi = ABI_NB32;
       else if (strcmp (arg, "64") == 0)
 	mips_abi = ABI_64;
       else if (strcmp (arg, "eabi") == 0)
@@ -15985,7 +16002,7 @@  mips_conditional_register_usage (void)
     }
   /* Odd registers in the range $f21-$f31 (inclusive) are call-clobbered
      for n32.  */
-  if (mips_abi == ABI_N32)
+  if (mips_abi == ABI_N32 || mips_abi == ABI_NB32)
     {
       int regno;
       for (regno = FP_REG_FIRST + 21; regno <= FP_REG_FIRST + 31; regno+=2)
@@ -16400,6 +16417,25 @@  mips_shift_truncation_mask (enum machine
   return GET_MODE_BITSIZE (mode) - 1;
 }
 
+void mips_expand_zero_extend_symbol (rtx dest, rtx sym)
+{
+  rtx t1, t2;
+
+  if (can_create_pseudo_p ())
+    {
+      t1 = gen_reg_rtx (DImode);
+      t2 = gen_reg_rtx (DImode);
+    }
+  else
+    {
+      t1 = dest;
+      t2 = dest;
+    }
+  emit_insn (gen_zero_extendsidi_high_address (t1, sym));
+  mips_emit_binary (ASHIFT, t2, t1, GEN_INT (16));
+  emit_insn (gen_zero_extendsidi_low_address (dest, t2, sym));
+}
+
 
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
Index: gcc/config/mips/mips.h
===================================================================
--- gcc/config/mips/mips.h	(revision 170267)
+++ gcc/config/mips/mips.h	(working copy)
@@ -43,6 +43,7 @@  extern int target_flags_explicit;
 #define ABI_64  2
 #define ABI_EABI 3
 #define ABI_O64  4
+#define ABI_NB32 5
 
 /* Masks that affect tuning.
 
@@ -303,7 +304,10 @@  enum mips_code_readable_setting {
 				     || TUNE_24K)
 
 #define TARGET_OLDABI		    (mips_abi == ABI_32 || mips_abi == ABI_O64)
-#define TARGET_NEWABI		    (mips_abi == ABI_N32 || mips_abi == ABI_64)
+#define TARGET_NEWABI		    (mips_abi == ABI_N32	\
+				     || mips_abi == ABI_NB32	\
+				     || mips_abi == ABI_64)
+#define TARGET_NB32		    (mips_abi == ABI_NB32)
 
 /* TARGET_HARD_FLOAT and TARGET_SOFT_FLOAT reflect whether the FPU is
    directly accessible, while the command-line options select
@@ -478,6 +482,11 @@  enum mips_code_readable_setting {
 	  builtin_define ("_ABIO64=4");					\
 	  builtin_define ("_MIPS_SIM=_ABIO64");				\
 	  break;							\
+									\
+	case ABI_NB32:							\
+	  builtin_define ("_ABINB32=5");				\
+	  builtin_define ("_MIPS_SIM=_ABINB32");			\
+	  break;							\
 	}								\
 									\
       builtin_define_with_int_value ("_MIPS_SZINT", INT_TYPE_SIZE);	\
@@ -669,6 +678,10 @@  enum mips_code_readable_setting {
 #define MULTILIB_ABI_DEFAULT "mabi=n32"
 #endif
 
+#if MIPS_ABI_DEFAULT == ABI_NB32
+#define MULTILIB_ABI_DEFAULT "mabi=nb32"
+#endif
+
 #if MIPS_ABI_DEFAULT == ABI_64
 #define MULTILIB_ABI_DEFAULT "mabi=64"
 #endif
@@ -742,6 +755,7 @@  enum mips_code_readable_setting {
 
 #if MIPS_ABI_DEFAULT == ABI_O64 \
   || MIPS_ABI_DEFAULT == ABI_N32 \
+  || MIPS_ABI_DEFAULT == ABI_NB32 \
   || MIPS_ABI_DEFAULT == ABI_64
 #define OPT_ARCH64 "mabi=32|mgp32:;"
 #define OPT_ARCH32 "mabi=32|mgp32"
@@ -1475,7 +1489,7 @@  enum mips_code_readable_setting {
 
 /* Pmode is always the same as ptr_mode, but not always the same as word_mode.
    Extensions of pointers to word_mode must be signed.  */
-#define POINTERS_EXTEND_UNSIGNED false
+#define POINTERS_EXTEND_UNSIGNED TARGET_NB32
 
 /* Define if loading short immediate values into registers sign extends.  */
 #define SHORT_IMMEDIATES_SIGN_EXTEND
@@ -2430,7 +2444,8 @@  typedef struct mips_args {
    between pointers and any other objects of this machine mode.  */
 
 #ifndef Pmode
-#define Pmode (TARGET_64BIT && TARGET_LONG64 ? DImode : SImode)
+#define Pmode (TARGET_64BIT && TARGET_LONG64 ? DImode : \
+	       (TARGET_NB32 ? DImode : SImode))
 #endif
 
 /* Give call MEMs SImode since it is the "most permissive" mode
Index: gcc/config/mips/netbsd.h
===================================================================
--- gcc/config/mips/netbsd.h	(revision 170267)
+++ gcc/config/mips/netbsd.h	(working copy)
@@ -44,6 +44,8 @@  along with GCC; see the file COPYING3.  
 	builtin_define ("__mips_eabi");			\
       else if (mips_abi == ABI_N32)			\
 	builtin_define ("__mips_n32");			\
+      else if (mips_abi == ABI_NB32)			\
+	builtin_define ("__mips_nb32");			\
       else if (mips_abi == ABI_64)			\
 	builtin_define ("__mips_n64");			\
       else if (mips_abi == ABI_O64)			\