+ case R_SPARC_WDISP30:
+ do_wplt30:
+ if (SEC_DO_RELAX (input_section)
+ && rel->r_offset + 4 < input_section->_raw_size)
+ {
+#define G0 0
+#define O7 15
+#define XCC (2 << 20)
+#define COND(x) (((x)&0xf)<<25)
+#define CONDA COND(0x8)
+#define INSN_BPA (F2(0,1) | CONDA | BPRED | XCC)
+#define INSN_BA (F2(0,2) | CONDA)
+#define INSN_OR F3(2, 0x2, 0)
+#define INSN_NOP F2(0,4)
+
+ bfd_vma x, y;
+
+ /* If the instruction is a call with either:
+ restore
+ arithmetic instruction with rd == %o7
+ where rs1 != %o7 and rs2 if it is register != %o7
+ then we can optimize if the call destination is near
+ by changing the call into a branch always. */
+ x = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ y = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+ if ((x & OP(~0)) == OP(1) && (y & OP(~0)) == OP(2))
+ {
+ if (((y & OP3(~0)) == OP3(0x3d) /* restore */
+ || ((y & OP3(0x28)) == 0 /* arithmetic */
+ && (y & RD(~0)) == RD(O7)))
+ && (y & RS1(~0)) != RS1(O7)
+ && ((y & F3I(~0))
+ || (y & RS2(~0)) != RS2(O7)))
+ {
+ bfd_vma reloc;
+
+ reloc = relocation + rel->r_addend - rel->r_offset;
+ reloc -= (input_section->output_section->vma
+ + input_section->output_offset);
+ if (reloc & 3)
+ goto do_default;
+
+ /* Ensure the branch fits into simm22. */
+ if ((reloc & ~(bfd_vma)0x7fffff)
+ && ((reloc | 0x7fffff) != MINUS_ONE))
+ goto do_default;
+ reloc >>= 2;
+
+ /* Check whether it fits into simm19. */
+ if ((reloc & 0x3c0000) == 0
+ || (reloc & 0x3c0000) == 0x3c0000)
+ x = INSN_BPA | (reloc & 0x7ffff); /* ba,pt %xcc */
+ else
+ x = INSN_BA | (reloc & 0x3fffff); /* ba */
+ bfd_put_32 (input_bfd, x, contents + rel->r_offset);
+ r = bfd_reloc_ok;
+ if (rel->r_offset >= 4
+ && (y & (0xffffffff ^ RS1(~0)))
+ == (INSN_OR | RD(O7) | RS2(G0)))
+ {
+ bfd_vma z;
+ unsigned int reg;
+
+ z = bfd_get_32 (input_bfd,
+ contents + rel->r_offset - 4);
+ if ((z & (0xffffffff ^ RD(~0)))
+ != (INSN_OR | RS1(O7) | RS2(G0)))
+ break;
+
+ /* The sequence was
+ or %o7, %g0, %rN
+ call foo
+ or %rN, %g0, %o7
+
+ If call foo was replaced with ba, replace
+ or %rN, %g0, %o7 with nop. */
+
+ reg = (y & RS1(~0)) >> 14;
+ if (reg != ((z & RD(~0)) >> 25)
+ || reg == G0 || reg == O7)
+ break;
+
+ bfd_put_32 (input_bfd, INSN_NOP,
+ contents + rel->r_offset + 4);
+ }
+ break;
+ }
+ }
+ }
+ /* FALLTHROUGH */
+