+2008-02-02 Richard Sandiford <rsandifo@nildram.co.uk>
+
+ PR target/34981
+ * config/mips/mips-protos.h (mips_expand_call): Return an rtx.
+ (build_mips16_call_stub): Likewise.
+ * config/mips/mips.h (FIRST_PSEUDO_REGISTER): Rename FAKE_CALL_REGNO
+ to GOT_VERSION_REGNUM.
+ (CALL_REALLY_USED_REGISTERS): Set the GOT_VERSION_REGNUM entry to 0.
+ (EPILOGUE_USES): Include GOT_VERSION_REGNUM if TARGET_ABICALLS.
+ * config/mips/mips.c (mips_emit_call_insn): New function.
+ (mips_call_tls_get_addr): Call mips_expand_call directly.
+ (mips_expand_call): Update the call to build_mips16_call_stub
+ and remove a redundant condition. Assert that MIPS16 stubs do not
+ use lazy binding. Use mips_emit_call_insn and return the call insn.
+ (override_options): Allow SImode for GOT_VERSION_REGNUM.
+ (build_mips16_call_stub): Use mips_emit_call_insn rather than
+ emit_call_insn. Return the call insn or null.
+ (mips_avoid_hazard): Remove hazard_set handling.
+ (mips_extra_live_on_entry): Include GOT_VERSION_REGNUM if
+ TARGET_ABICALLS.
+ * config/mips/mips.md (UNSPEC_EH_RECEIVER): Rename to...
+ (UNSPEC_RESTORE_GP): ...this.
+ (UNSPEC_SET_GOT_VERSION, UNSPEC_UPDATE_GOT_VERSION): New constants.
+ (FAKE_CALL_REGNO): Rename to...
+ (GOT_VERSION_REGNUM): ...this.
+ (type): Add "ghost" value. Add an associated insn reservation.
+ (hazard_set): Remove.
+ (exception_receiver): Rename to...
+ (restore_gp): ...this and update the unspec identifier accordingly.
+ (exception_receiver, nonlocal_got_receiver): New expanders.
+ (load_call<mode>): Use GOT_VERSION_REGNUM. Don't set
+ FAKE_CALL_REGNO. Remove hazard_set attribute.
+ (set_got_version, update_got_version): New patterns.
+
2008-02-02 Richard Sandiford <rsandifo@nildram.co.uk>
PR target/31388
#endif
extern void gen_conditional_move (rtx *);
extern void mips_gen_conditional_trap (rtx *);
-extern void mips_expand_call (rtx, rtx, rtx, rtx, int);
+extern rtx mips_expand_call (rtx, rtx, rtx, rtx, int);
extern void mips_emit_fcc_reload (rtx, rtx, rtx);
extern void mips_set_return_address (rtx, rtx);
extern bool mips_expand_block_move (rtx, rtx, rtx);
enum machine_mode,
rtx, int);
extern int mips_class_max_nregs (enum reg_class, enum machine_mode);
-extern int build_mips16_call_stub (rtx, rtx, rtx, int);
+extern rtx build_mips16_call_stub (rtx, rtx, rtx, int);
extern int mips_register_move_cost (enum machine_mode, enum reg_class,
enum reg_class);
count++;
return count;
}
+
+/* Emit a call sequence with call pattern PATTERN and return the call
+ instruction itself (which is not necessarily the last instruction
+ emitted). LAZY_P is true if the call address is lazily-bound. */
+
+static rtx
+mips_emit_call_insn (rtx pattern, bool lazy_p)
+{
+ rtx insn;
+
+ insn = emit_call_insn (pattern);
+
+ /* Lazy-binding stubs require $gp to be valid on entry. */
+ if (lazy_p)
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
+
+ if (TARGET_ABICALLS)
+ {
+ /* See the comment above load_call<mode> for details. */
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn),
+ gen_rtx_REG (Pmode, GOT_VERSION_REGNUM));
+ emit_insn (gen_update_got_version ());
+ }
+ return insn;
+}
\f
/* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
returns a nonzero value if X is a legitimate address for a memory
static rtx
mips_call_tls_get_addr (rtx sym, enum mips_symbol_type type, rtx v0)
{
- rtx insn, loc, tga, a0;
+ rtx insn, loc, a0;
a0 = gen_rtx_REG (Pmode, GP_ARG_FIRST);
emit_insn (gen_rtx_SET (Pmode, a0,
gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, loc)));
- tga = gen_rtx_MEM (Pmode, mips_tls_symbol);
- insn = emit_call_insn (gen_call_value (v0, tga, const0_rtx, const0_rtx));
+ insn = mips_expand_call (v0, mips_tls_symbol, const0_rtx, const0_rtx, false);
CONST_OR_PURE_CALL_P (insn) = 1;
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), v0);
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), a0);
function, ARGS_SIZE is the size of the arguments and AUX is
the value passed to us by mips_function_arg. SIBCALL_P is true
if we are expanding a sibling call, false if we're expanding
- a normal call. */
+ a normal call.
-void
+ Return the call itself. */
+
+rtx
mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, int sibcall_p)
{
rtx orig_addr, pattern, insn;
lazy_p = mips_load_call_address (addr, orig_addr, sibcall_p);
}
- if (TARGET_MIPS16
- && mips16_hard_float
- && build_mips16_call_stub (result, addr, args_size,
- aux == 0 ? 0 : (int) GET_MODE (aux)))
- return;
+ insn = build_mips16_call_stub (result, addr, args_size,
+ aux == 0 ? 0 : (int) GET_MODE (aux));
+ if (insn)
+ {
+ gcc_assert (!sibcall_p && !lazy_p);
+ return insn;
+ }
if (result == 0)
pattern = (sibcall_p
? gen_sibcall_value_internal (result, addr, args_size)
: gen_call_value_internal (result, addr, args_size));
- insn = emit_call_insn (pattern);
-
- /* Lazy-binding stubs require $gp to be valid on entry. We also pretend
- that they use FAKE_CALL_REGNO; see the load_call<mode> patterns for
- details. */
- if (lazy_p)
- {
- use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
- use_reg (&CALL_INSN_FUNCTION_USAGE (insn),
- gen_rtx_REG (Pmode, FAKE_CALL_REGNO));
- }
+ return mips_emit_call_insn (pattern, lazy_p);
}
else if (ALL_COP_REG_P (regno))
temp = (class == MODE_INT && size <= UNITS_PER_WORD);
+
+ else if (regno == GOT_VERSION_REGNUM)
+ temp = (mode == SImode);
+
else
temp = 0;
RETVAL is the location of the return value, or null if this is
a call rather than a call_value. FN is the address of the
function and ARG_SIZE is the size of the arguments. FP_CODE
- is the code built by function_arg. This function returns a nonzero
- value if it builds the call instruction itself. */
+ is the code built by function_arg.
-int
+ If a stub was needed, emit the call and return the call insn itself.
+ Return null otherwise. */
+
+rtx
build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
{
int fpret;
/* We don't need to do anything if we aren't in mips16 mode, or if
we were invoked with the -msoft-float option. */
if (! TARGET_MIPS16 || ! mips16_hard_float)
- return 0;
+ return NULL_RTX;
/* Figure out whether the value might come back in a floating point
register. */
arguments and the value will not be returned in a floating point
register. */
if (fp_code == 0 && ! fpret)
- return 0;
+ return NULL_RTX;
/* We don't need to do anything if this is a call to a special
mips16 support function. */
if (GET_CODE (fn) == SYMBOL_REF
&& strncmp (XSTR (fn, 0), "__mips16_", 9) == 0)
- return 0;
+ return NULL_RTX;
/* This code will only work for o32 and o64 abis. The other ABI's
require more sophisticated support. */
insn = gen_call_internal (stub_fn, arg_size);
else
insn = gen_call_value_internal (retval, stub_fn, arg_size);
- insn = emit_call_insn (insn);
+ insn = mips_emit_call_insn (insn, false);
/* Put the register usage information on the CALL. */
CALL_INSN_FUNCTION_USAGE (insn) =
/* Return 1 to tell the caller that we've generated the call
insn. */
- return 1;
+ return insn;
}
/* We know the function we are going to call. If we have already
insn = gen_call_internal (fn, arg_size);
else
insn = gen_call_value_internal (retval, fn, arg_size);
- insn = emit_call_insn (insn);
+ insn = mips_emit_call_insn (insn, false);
CALL_INSN_FUNCTION_USAGE (insn) =
gen_rtx_EXPR_LIST (VOIDmode,
/* Return 1 to tell the caller that we've generated the call
insn. */
- return 1;
+ return insn;
}
/* Return 0 to let the caller generate the call insn. */
- return 0;
+ return NULL_RTX;
}
/* An entry in the mips16 constant pool. VALUE is the pool constant,
rtx *delayed_reg, rtx lo_reg)
{
rtx pattern, set;
- int nops, ninsns, hazard_set;
+ int nops, ninsns;
pattern = PATTERN (insn);
break;
case HAZARD_DELAY:
- hazard_set = (int) get_attr_hazard_set (insn);
- if (hazard_set == 0)
- set = single_set (insn);
- else
- {
- gcc_assert (GET_CODE (PATTERN (insn)) == PARALLEL);
- set = XVECEXP (PATTERN (insn), 0, hazard_set - 1);
- }
- gcc_assert (set && GET_CODE (set) == SET);
+ set = single_set (insn);
+ gcc_assert (set);
*delayed_reg = SET_DEST (set);
break;
}
}
}
-/* Implement TARGET_EXTRA_LIVE_ON_ENTRY. PIC_FUNCTION_ADDR_REGNUM is live
- on entry to a function when generating -mshared abicalls code. */
+/* Implement TARGET_EXTRA_LIVE_ON_ENTRY. */
static void
mips_extra_live_on_entry (bitmap regs)
{
- if (TARGET_ABICALLS && !TARGET_ABSOLUTE_ABICALLS)
- bitmap_set_bit (regs, PIC_FUNCTION_ADDR_REGNUM);
+ if (TARGET_ABICALLS)
+ {
+ /* PIC_FUNCTION_ADDR_REGNUM is live if we need it to set up
+ the global pointer. */
+ if (!TARGET_ABSOLUTE_ABICALLS)
+ bitmap_set_bit (regs, PIC_FUNCTION_ADDR_REGNUM);
+
+ /* See the comment above load_call<mode> for details. */
+ bitmap_set_bit (regs, GOT_VERSION_REGNUM);
+ }
}
/* SImode values are represented as sign-extended to DImode. */
- 3 fake registers:
- ARG_POINTER_REGNUM
- FRAME_POINTER_REGNUM
- - FAKE_CALL_REGNO (see the comment above load_callsi for details)
+ - GOT_VERSION_REGNUM (see the comment above load_call<mode> for details)
- 3 dummy entries that were used at various times in the past.
- 6 DSP accumulator registers (3 hi-lo pairs) for MIPS DSP ASE
- 6 DSP control registers */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
/* Others. */ \
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, \
/* COP0 registers */ \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
\f
/* Say that the epilogue uses the return address register. Note that
in the case of sibcalls, the values "used by the epilogue" are
- considered live at the start of the called function. */
-#define EPILOGUE_USES(REGNO) ((REGNO) == 31)
+ considered live at the start of the called function.
+
+ If using a GOT, say that the epilogue also uses GOT_VERSION_REGNUM.
+ See the comment above load_call<mode> for details. */
+#define EPILOGUE_USES(REGNO) \
+ ((REGNO) == 31 || (TARGET_ABICALLS && (REGNO) == GOT_VERSION_REGNUM))
/* Treat LOC as a byte offset from the stack pointer and round it up
to the next fully-aligned offset. */
(UNSPEC_GET_FNADDR 3)
(UNSPEC_BLOCKAGE 4)
(UNSPEC_CPRESTORE 5)
- (UNSPEC_EH_RECEIVER 6)
+ (UNSPEC_RESTORE_GP 6)
(UNSPEC_EH_RETURN 7)
(UNSPEC_CONSTTABLE_INT 8)
(UNSPEC_CONSTTABLE_FLOAT 9)
(UNSPEC_MFHILO 26)
(UNSPEC_TLS_LDM 27)
(UNSPEC_TLS_GET_TP 28)
+ (UNSPEC_SET_GOT_VERSION 29)
+ (UNSPEC_UPDATE_GOT_VERSION 30)
(UNSPEC_ADDRESS_FIRST 100)
- (FAKE_CALL_REGNO 79)
+ (GOT_VERSION_REGNUM 79)
;; For MIPS Paired-Singled Floating Point Instructions.
;; frsqrt2 floating point reciprocal square root step2
;; multi multiword sequence (or user asm statements)
;; nop no operation
+;; ghost an instruction that produces no real code
(define_attr "type"
- "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,prefetch,prefetchx,condmove,xfer,mthilo,mfhilo,const,arith,shift,slt,clz,trap,imul,imul3,imadd,idiv,fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,frsqrt,frsqrt1,frsqrt2,multi,nop"
+ "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,prefetch,prefetchx,condmove,xfer,mthilo,mfhilo,const,arith,shift,slt,clz,trap,imul,imul3,imadd,idiv,fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,frsqrt,frsqrt1,frsqrt2,multi,nop,ghost"
(cond [(eq_attr "jal" "!unset") (const_string "call")
(eq_attr "got" "load") (const_string "load")]
(const_string "unknown")))
(const_string "hilo")]
(const_string "none")))
-;; Indicates which SET in an instruction pattern induces a hazard.
-;; Only meaningful when "hazard" is not "none". SINGLE means that
-;; the pattern has only one set while the other values are indexes
-;; into a PARALLEL vector.
-;;
-;; Hazardous instructions with multiple sets should generally put the
-;; hazardous set first. The only purpose of this attribute is to force
-;; each multi-set pattern to explicitly assert that this condition holds.
-(define_attr "hazard_set" "single,0"
- (const_string "single"))
-
;; Is it a single instruction?
(define_attr "single_insn" "no,yes"
(symbol_ref "get_attr_length (insn) == (TARGET_MIPS16 ? 2 : 4)"))
(define_cpu_unit "alu" "alu")
(define_cpu_unit "imuldiv" "imuldiv")
+;; Ghost instructions produce no real code and introduce no hazards.
+;; They exist purely to express an effect on dataflow.
+(define_insn_reservation "ghost" 0
+ (eq_attr "type" "ghost")
+ "nothing")
+
(include "4k.md")
(include "5k.md")
(include "24k.md")
DONE;
})
-(define_insn_and_split "exception_receiver"
+(define_expand "exception_receiver"
+ [(const_int 0)]
+ "TARGET_ABICALLS"
+{
+ /* See the comment above load_call<mode> for details. */
+ emit_insn (gen_set_got_version ());
+
+ /* If we have a call-clobbered $gp, restore it from its save slot. */
+ if (HAVE_restore_gp)
+ emit_insn (gen_restore_gp ());
+ DONE;
+})
+
+(define_expand "nonlocal_goto_receiver"
+ [(const_int 0)]
+ "TARGET_ABICALLS"
+{
+ /* See the comment above load_call<mode> for details. */
+ emit_insn (gen_set_got_version ());
+ DONE;
+})
+
+;; Restore $gp from its .cprestore stack slot. The instruction remains
+;; volatile until all uses of $28 are exposed.
+(define_insn_and_split "restore_gp"
[(set (reg:SI 28)
- (unspec_volatile:SI [(const_int 0)] UNSPEC_EH_RECEIVER))]
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_RESTORE_GP))]
"TARGET_ABICALLS && TARGET_OLDABI"
"#"
"&& reload_completed"
;; potentially modify the GOT entry. And once a stub has been called,
;; we must not call it again.
;;
-;; We represent this restriction using an imaginary fixed register that
-;; is set by the GOT load and used by the call. By making this register
-;; call-clobbered, and by making the GOT load the only way of setting
-;; the register, we ensure that the load cannot be moved past a call.
+;; We represent this restriction using an imaginary, fixed, call-saved
+;; register called GOT_VERSION_REGNUM. The idea is to make the register
+;; live throughout the function and to change its value after every
+;; potential call site. This stops any rtx value that uses the register
+;; from being computed before an earlier call. To do this, we:
+;;
+;; - Ensure that the register is live on entry to the function,
+;; so that it is never thought to be used uninitalized.
+;;
+;; - Ensure that the register is live on exit from the function,
+;; so that it is live throughout.
+;;
+;; - Make each call (lazily-bound or not) use the current value
+;; of GOT_VERSION_REGNUM, so that updates of the register are
+;; not moved across call boundaries.
+;;
+;; - Add "ghost" definitions of the register to the beginning of
+;; blocks reached by EH and ABNORMAL_CALL edges, because those
+;; edges may involve calls that normal paths don't. (E.g. the
+;; unwinding code that handles a non-call exception may change
+;; lazily-bound GOT entries.) We do this by making the
+;; exception_receiver and nonlocal_goto_receiver expanders emit
+;; a set_got_version instruction.
+;;
+;; - After each call (lazily-bound or not), use a "ghost"
+;; update_got_version instruction to change the register's value.
+;; This instruction mimics the _possible_ effect of the dynamic
+;; resolver during the call and it remains live even if the call
+;; itself becomes dead.
+;;
+;; - Leave GOT_VERSION_REGNUM out of all register classes.
+;; The register is therefore not a valid register_operand
+;; and cannot be moved to or from other registers.
(define_insn "load_call<mode>"
[(set (match_operand:P 0 "register_operand" "=c")
(unspec:P [(match_operand:P 1 "register_operand" "r")
- (match_operand:P 2 "immediate_operand" "")]
- UNSPEC_LOAD_CALL))
- (set (reg:P FAKE_CALL_REGNO)
- (unspec:P [(match_dup 2)] UNSPEC_LOAD_CALL))]
+ (match_operand:P 2 "immediate_operand" "")
+ (reg:SI GOT_VERSION_REGNUM)] UNSPEC_LOAD_CALL))]
"TARGET_ABICALLS"
"<load>\t%0,%R2(%1)"
[(set_attr "type" "load")
(set_attr "mode" "<MODE>")
- (set_attr "hazard_set" "0")
(set_attr "length" "4")])
+(define_insn "set_got_version"
+ [(set (reg:SI GOT_VERSION_REGNUM)
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_SET_GOT_VERSION))]
+ "TARGET_ABICALLS"
+ ""
+ [(set_attr "length" "0")
+ (set_attr "type" "ghost")])
+
+(define_insn "update_got_version"
+ [(set (reg:SI GOT_VERSION_REGNUM)
+ (unspec:SI [(reg:SI GOT_VERSION_REGNUM)] UNSPEC_UPDATE_GOT_VERSION))]
+ "TARGET_ABICALLS"
+ ""
+ [(set_attr "length" "0")
+ (set_attr "type" "ghost")])
+
;; Sibling calls. All these patterns use jump instructions.
;; If TARGET_SIBCALLS, call_insn_operand will only accept constant
+2008-02-02 Richard Sandiford <rsandifo@nildram.co.uk>
+
+ PR target/34981
+ * gcc.target/mips/lazy-binding-1.c: New test.
+ * gcc.target/mips/mips.exp (setup_mips_tests): Set mips_abi,
+ mips_forced_gp, mips_forced_no_abicalls, mips_forced_no_shared
+ and mips_forced_no_er.
+ (dg-mips-options): Avoid using -mips16 -mhard-float for ABIs
+ other than o32 and o64. Avoid using -mabicalls with an implicit
+ -mabi=eabi. Avoid using small data with -mabicalls. Skip
+ -mabi=*, -G*, -mabicalls, -mshared and -mexplicit-relocs tests
+ if the multilib forces the an incompatible option.
+
2008-02-01 Release Manager
* GCC 4.2.3 released.
--- /dev/null
+/* { dg-mips-options "-mabicalls -mshared -mexplicit-relocs -O2 -fno-delayed-branch" } */
+
+void bar (void);
+
+void
+foo (int n)
+{
+ while (n--)
+ {
+ bar ();
+ bar ();
+ }
+}
+
+/* There should be exactly five uses of $25: one to set up $gp, two to
+ load the address of bar (), and two to call it. */
+/* { dg-final { scan-assembler-times "\tl.\t\\\$25,%call16\\\(bar\\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\tjalr\t\\\$25" 2 } } */
+/* { dg-final { scan-assembler "(\\\$28,|\t.cpload\t)\\\$25" } } */
+/* { dg-final { scan-assembler-times "\\\$25" 5 } } */
# $mips_mips16: true if MIPS16 mode is selected
# $mips_mips64: true if 64-bit output is selected
# $mips_float: "hard" or "soft"
+# $mips_abi: the ABI specified by _MIPS_SIM
#
# $mips_forced_isa: true if the command line uses -march=* or -mips*
# $mips_forced_abi: true if the command line uses -mabi=* or -mgp*
# $mips_forced_float: true if the command line uses -mhard/soft-float
# $mips_forced_le true if the command line uses -EL or -mel
+# $mips_forced_gp true if the command line forces a particular GP mode
+# $mips_forced_no_abicalls
+# true if the command line contains -mno-abicalls
+# $mips_forced_no_shared
+# true if the command line contains -mno-shared
+# $mips_forced_no_er true if the command line contains -mno-explicit-relocs
proc setup_mips_tests {} {
global mips_isa
global mips_arch
global mips_mips16
global mips_mips64
global mips_float
+ global mips_abi
global mips_forced_isa
global mips_forced_abi
global mips_forced_float
global mips_forced_le
+ global mips_forced_gp
+ global mips_forced_no_abicalls
+ global mips_forced_no_shared
+ global mips_forced_no_er
global compiler_flags
global tool
#else
const char *float = "soft";
#endif
+ #if !defined _MIPS_SIM
+ const char *abi = "unknown";
+ #elif _MIPS_SIM==_ABIO32
+ const char *abi = "32";
+ #elif _MIPS_SIM==_ABIO64
+ const char *abi = "o64";
+ #elif _MIPS_SIM==_ABIN32
+ const char *abi = "n32";
+ #else
+ const char *abi = "64";
+ #endif
}
close $f
set output [${tool}_target_compile $src "" preprocess ""]
set mips_mips16 [regexp {mips16 = 1} $output]
set mips_mips64 [regexp {mips64 = 1} $output]
regexp {float = "([^"]*)} $output dummy mips_float
+ regexp {abi = "([^"]*)} $output dummy mips_abi
set mips_forced_isa [regexp -- {(-mips|-march)} $compiler_flags]
set mips_forced_abi [regexp -- {(-mgp|-mabi)} $compiler_flags]
set mips_forced_float [regexp -- {-m(hard|soft)-float} $compiler_flags]
set mips_forced_le [regexp -- {-(EL|mel)[[:>:]]} $compiler_flags]
+ set mips_forced_gp [regexp -- {-(G|mabicalls)} $compiler_flags]
+ set mips_forced_no_abicalls [regexp -- {-mno-abicalls} $compiler_flags]
+ set mips_forced_no_shared [regexp -- {-mno-shared} $compiler_flags]
+ set mips_forced_no_er [regexp -- {-mno-explicit-relocs} $compiler_flags]
}
# Return true if command-line option FLAG forces 32-bit code.
# -mno-mips16
# Skip the test for MIPS16 targets.
#
+# -mabi=*
+# Force a particular ABI. Skip the test if the multilib flags
+# force a specific ABI or a different register size. If testing
+# MIPS16 multilibs, try to force -msoft-float for ABIs other than
+# o32 and o64, and skip the test if this is not possible.
+#
# -march=*
# -mips*
# Select the target architecture. Skip the test for MIPS16 targets
# -EB
# Select big-endian code. Skip the test if the multilib flags
# force a little-endian target.
+#
+# -G*
+# Select the small-data mode, and -mno-abcialls. Skip the test if
+# the multilib flags already contain such an option, or specify
+# something that might be incompatible with them.
+#
+# -mabicalls
+# -mshared
+# Select the form of SVR4 PIC. Skip the test if the multilib flags
+# conflict with the required setting.
+#
+# -mexplicit-relocs
+# Select explicit relocations. Skip the test if the multilib flags
+# force -mno-explicit-relocs.
proc dg-mips-options {args} {
upvar dg-extra-tool-flags extra_tool_flags
upvar dg-do-what do_what
global mips_mips16
global mips_mips64
global mips_float
+ global mips_abi
global mips_forced_isa
global mips_forced_abi
global mips_forced_float
global mips_forced_le
+ global mips_forced_gp
+ global mips_forced_no_abicalls
+ global mips_forced_no_shared
+ global mips_forced_no_er
set flags [lindex $args 1]
set matches 1
- # First handle the -mgp* options. Add an architecture option if necessary.
+ foreach flag $flags {
+ if {[regexp -- {^-mabi=(.*)} $flag dummy abi]
+ && $mips_mips16
+ && $abi != "32"
+ && $abi != "o64"} {
+ if {[lsearch $flags -mhard-float] >= 0} {
+ set matches 0
+ } else {
+ append flags " -msoft-float"
+ }
+ }
+ }
+
+ # Handle the -mgp* options. Add an architecture option if necessary.
foreach flag $flags {
if {[is_gp32_flag $flag] && $mips_mips64} {
if {$mips_forced_abi} {
}
}
}
+
+ foreach flag $flags {
+ if {[string match -mabicalls $flag]} {
+ # EABI has no SVR4-style PIC mode, so if we don't know for
+ # sure what the default ABI is, try to force an appropriate one.
+ if {$mips_abi == "unknown" && [lsearch $flags "-mabi=*"] < 0} {
+ if {!$mips_mips64} {
+ append flags " -mabi=32"
+ } else {
+ append flags " -mabi=n32"
+ }
+ }
+ # Turn off small data, if on by default. Also turn off
+ # MIPS16 code generation. (We don't support -mabicalls
+ # with either.)
+ append flags " -G0 -mno-mips16"
+ }
+ }
+
# Handle the other options.
foreach flag $flags {
if {$flag == "-mno-mips16"} {
if {$mips_mips16} {
set matches 0
}
+ } elseif {[regexp -- {^-mabi=(.*)} $flag dummy abi]} {
+ if {$abi != $mips_abi && $mips_forced_abi} {
+ set matches 0
+ }
} elseif {[regexp -- {^-march=(.*)} $flag dummy arch]} {
if {$mips_mips16 || ($arch != $mips_arch && $mips_forced_isa)} {
set matches 0
if {$mips_forced_le} {
set matches 0
}
+ } elseif {[regexp -- {^-G} $flag]} {
+ if {$flag != "-G0"} {
+ append flags " -mno-abicalls"
+ }
+ if {$mips_forced_gp} {
+ set matches 0
+ }
+ } elseif {[regexp -- {^-mabicalls$} $flag]} {
+ if {$mips_forced_no_abicalls} {
+ set matches 0
+ }
+ } elseif {[regexp -- {^-mshared$} $flag]} {
+ if {$mips_forced_no_shared} {
+ set matches 0
+ }
+ } elseif {[regexp -- {^-mexplicit-relocs$} $flag]} {
+ if {$mips_forced_no_er} {
+ set matches 0
+ }
}
}
if {$matches} {