- /* Filling the branch delay slot is more complex. We try to
- switch the branch with the previous instruction, which we can
- do if the previous instruction does not set up a condition
- that the branch tests and if the branch is not itself the
- target of any branch. */
- if ((pinfo & INSN_UNCOND_BRANCH_DELAY)
- || (pinfo & INSN_COND_BRANCH_DELAY))
- {
- if (mips_optimize < 2
- /* If we have seen .set volatile or .set nomove, don't
- optimize. */
- || mips_opts.nomove != 0
- /* We can't swap if the previous instruction's position
- is fixed. */
- || history[0].fixed_p
- /* 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. */
- || history[1].noreorder_p
- /* 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
- there are any branches to anything other than a
- label, users must use .set noreorder. */
- || si->label_list != NULL
- /* If the previous instruction is in a variant frag
- other than this branch's one, we cannot do the swap.
- This does not apply to the mips16, which uses variant
- frags for different purposes. */
- || (! mips_opts.mips16
- && prev_insn_frag_type == rs_machine_dependent)
- /* Check for conflicts between the branch and the instructions
- before the candidate delay slot. */
- || nops_for_insn (0, history + 1, ip) > 0
- /* Check for conflicts between the swapped sequence and the
- target of the branch. */
- || nops_for_sequence (2, 0, history + 1, ip, history) > 0
- /* We do not swap with a trap instruction, since it
- complicates trap handlers to have the trap
- instruction be in a delay slot. */
- || (prev_pinfo & INSN_TRAP)
- /* If the branch reads a register that the previous
- instruction sets, we can not swap. */
- || (gpr_read_mask (ip) & gpr_write_mask (&history[0])) != 0
- /* If the branch writes a register that the previous
- instruction sets, we can not swap. */
- || (gpr_write_mask (ip) & gpr_write_mask (&history[0])) != 0
- /* If the branch writes a register that the previous
- instruction reads, we can not swap. */
- || (gpr_write_mask (ip) & gpr_read_mask (&history[0])) != 0
- /* If one instruction sets a condition code and the
- other one uses a condition code, we can not swap. */
- || ((pinfo & INSN_READ_COND_CODE)
- && (prev_pinfo & INSN_WRITE_COND_CODE))
- || ((pinfo & INSN_WRITE_COND_CODE)
- && (prev_pinfo & INSN_READ_COND_CODE))
- /* If the previous instruction uses the PC, we can not
- swap. */
- || (mips_opts.mips16
- && (prev_pinfo & MIPS16_INSN_READ_PC))
- /* If the previous instruction had a fixup in mips16
- mode, we can not swap. This normally means that the
- previous instruction was a 4 byte branch anyhow. */
- || (mips_opts.mips16 && history[0].fixp[0])
- /* If the previous instruction is a sync, sync.l, or
- sync.p, we can not swap. */
- || (prev_pinfo & INSN_SYNC)
- /* If the previous instruction is an ERET or
- DERET, avoid the swap. */
- || (history[0].insn_opcode == INSN_ERET)
- || (history[0].insn_opcode == INSN_DERET))
- {
- if (mips_opts.mips16
- && (pinfo & INSN_UNCOND_BRANCH_DELAY)
- && (pinfo & (MIPS16_INSN_READ_X | MIPS16_INSN_READ_31))
- && ISA_SUPPORTS_MIPS16E)
- {
- /* Convert MIPS16 jr/jalr into a "compact" jump. */
- ip->insn_opcode |= 0x0080;
- find_altered_mips16_opcode (ip);
- install_insn (ip);
- insert_into_history (0, 1, ip);
- }
- else
- {
- /* We could do even better for unconditional branches to
- portions of this object file; we could pick up the
- instruction at the destination, put it in the delay
- slot, and bump the destination address. */
- insert_into_history (0, 1, ip);
- emit_nop ();
- }
-
- if (mips_relax.sequence)
- mips_relax.sizes[mips_relax.sequence - 1] += 4;
- }
- else
- {
- /* It looks like we can actually do the swap. */
- struct mips_cl_insn delay = history[0];
- if (mips_opts.mips16)
- {
- know (delay.frag == ip->frag);
- move_insn (ip, delay.frag, delay.where);
- move_insn (&delay, ip->frag, ip->where + insn_length (ip));
- }
- else if (relaxed_branch)
- {
- /* Add the delay slot instruction to the end of the
- current frag and shrink the fixed part of the
- original frag. If the branch occupies the tail of
- the latter, move it backwards to cover the gap. */
- delay.frag->fr_fix -= 4;
- if (delay.frag == ip->frag)
- move_insn (ip, ip->frag, ip->where - 4);
- add_fixed_insn (&delay);
- }
- else
- {
- move_insn (&delay, ip->frag, ip->where);
- move_insn (ip, history[0].frag, history[0].where);
- }
- history[0] = *ip;
- delay.fixed_p = 1;
- insert_into_history (0, 1, &delay);
- }
- }
- else if (pinfo & INSN_COND_BRANCH_LIKELY)
- {
- /* We don't yet optimize a branch likely. What we should do
- is look at the target, copy the instruction found there
- into the delay slot, and increment the branch to jump to
- the next instruction. */
- insert_into_history (0, 1, ip);
- emit_nop ();
- }
- else
- insert_into_history (0, 1, ip);
+ case APPEND_ADD:
+ insert_into_history (0, 1, ip);
+ break;
+
+ case APPEND_ADD_WITH_NOP:
+ insert_into_history (0, 1, ip);
+ emit_nop ();
+ if (mips_relax.sequence)
+ mips_relax.sizes[mips_relax.sequence - 1] += 4;
+ break;
+
+ case APPEND_ADD_COMPACT:
+ /* Convert MIPS16 jr/jalr into a "compact" jump. */
+ gas_assert (mips_opts.mips16);
+ ip->insn_opcode |= 0x0080;
+ find_altered_mips16_opcode (ip);
+ install_insn (ip);
+ insert_into_history (0, 1, ip);
+ break;
+
+ case APPEND_SWAP:
+ {
+ struct mips_cl_insn delay = history[0];
+ if (mips_opts.mips16)
+ {
+ know (delay.frag == ip->frag);
+ move_insn (ip, delay.frag, delay.where);
+ move_insn (&delay, ip->frag, ip->where + insn_length (ip));
+ }
+ else if (relaxed_branch)
+ {
+ /* Add the delay slot instruction to the end of the
+ current frag and shrink the fixed part of the
+ original frag. If the branch occupies the tail of
+ the latter, move it backwards to cover the gap. */
+ delay.frag->fr_fix -= 4;
+ if (delay.frag == ip->frag)
+ move_insn (ip, ip->frag, ip->where - 4);
+ add_fixed_insn (&delay);
+ }
+ else
+ {
+ move_insn (&delay, ip->frag, ip->where);
+ move_insn (ip, history[0].frag, history[0].where);
+ }
+ history[0] = *ip;
+ delay.fixed_p = 1;
+ insert_into_history (0, 1, &delay);
+ }
+ break;