aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gas/config/tc-mips.c52
1 files changed, 49 insertions, 3 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index db0671e..bb4c48e 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -102,6 +102,11 @@ static symbolS *insn_label;
/* To output NOP instructions correctly, we need to keep information
about the previous two instructions. */
+/* Whether we are optimizing. We always optimize unless -O0 is given.
+ For the very simple optimizations we do, this is compatible with
+ the MIPS assembler. */
+static int mips_optimize = 1;
+
/* The previous instruction. */
static struct mips_cl_insn prev_insn;
@@ -126,6 +131,13 @@ static fixS *prev_insn_fixp;
/* Non-zero if the previous instruction was in a delay slot. */
static int prev_insn_is_delay_slot;
+
+/* Non-zero if the previous instruction was in a .set noreorder. */
+static int prev_insn_unreordered;
+
+/* Non-zero if the previous previous instruction was in a .set
+ noreorder. */
+static int prev_prev_insn_unreordered;
/* Prototypes for static functions. */
@@ -613,15 +625,33 @@ append_insn (ip, address_expr, reloc_type)
if ((ip->insn_mo->pinfo & INSN_UNCOND_BRANCH_DELAY)
|| (ip->insn_mo->pinfo & INSN_COND_BRANCH_DELAY))
{
- /* If we had to emit any NOP instructions, then we already
- know we can not swap. */
- if (nops != 0
+ if (! mips_optimize
+ /* If we had to emit any NOP instructions, then we
+ already know we can not swap. */
+ || nops != 0
/* If we don't even know the previous insn, we can not
swap. */
|| ! prev_insn_valid
/* If the previous insn is already in a branch delay
slot, then we can not swap. */
|| prev_insn_is_delay_slot
+ /* If the previous previous insn was in a .set
+ noreorder, we can't swap. Actually, the MIPS
+ assembler will swap in this situation. However, gcc
+ configured -with-gnu-as will generate code like
+ .set noreorder
+ lw $4,XXX
+ .set reorder
+ INSN
+ bne $4,$0,foo
+ in which we can not swap the bne and INSN. If gcc is
+ not configured -with-gnu-as, it does not output the
+ .set pseudo-ops. We don't have to check
+ prev_insn_unreordered, because prev_insn_valid will
+ be 0 in that case. We don't want to use
+ prev_prev_insn_valid, because we do want to be able
+ to swap at the start of a function. */
+ || prev_prev_insn_unreordered
/* If the branch is itself the target of a branch, we
can not swap. We cheat on this; all we check for is
whether there is a label on this instruction. If
@@ -738,6 +768,8 @@ append_insn (ip, address_expr, reloc_type)
prev_insn_is_delay_slot = 0;
}
+ prev_prev_insn_unreordered = prev_insn_unreordered;
+ prev_insn_unreordered = 0;
prev_insn_frag = frag_now;
prev_insn_where = f - frag_now->fr_literal;
prev_insn_fixp = fixp;
@@ -758,6 +790,8 @@ mips_no_prev_insn ()
prev_prev_insn.insn_mo = &dummy_opcode;
prev_insn_valid = 0;
prev_insn_is_delay_slot = 0;
+ prev_insn_unreordered = 0;
+ prev_prev_insn_unreordered = 0;
insn_label = NULL;
}
@@ -2965,6 +2999,12 @@ md_parse_option (argP, cntP, vecP)
return 1;
}
+ if (**argP == 'O')
+ {
+ mips_optimize = (*argP)[1] != '0';
+ return 1;
+ }
+
#ifdef OBJ_ECOFF
if (**argP == 'G')
{
@@ -2983,6 +3023,7 @@ md_parse_option (argP, cntP, vecP)
return 1;
}
#endif
+
return 1; /* pretend you parsed the character */
}
@@ -3356,6 +3397,11 @@ s_mipsset (x)
if (strcmp (name, "reorder") == 0)
{
+ if (mips_noreorder)
+ {
+ prev_insn_unreordered = 1;
+ prev_prev_insn_unreordered = 1;
+ }
mips_noreorder = 0;
}
else if (strcmp (name, "noreorder") == 0)