===================================================================
@@ -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>")])
===================================================================
@@ -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 */
===================================================================
@@ -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
===================================================================
@@ -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
===================================================================
@@ -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) \