[mips] Fix MipsLongBranch pass to work when the offset from the branch to the

target cannot be determined accurately. This is the case for NaCl where the
sandboxing instructions are added in MC layer, after the MipsLongBranch pass.
It is also the case when the code has inline assembly. Instead of calculating
offset in the MipsLongBranch pass, use %hi(sym1 - sym2) and %lo(sym1 - sym2)
expressions that are resolved during the fixup.

This patch also deletes microMIPS test file test/CodeGen/Mips/micromips-long-branch.ll
and implements microMIPS CHECKs in a much simpler way in a file
test/CodeGen/Mips/longbranch.ll, together with MIPS32 and MIPS64.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@207656 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sasa Stankovic 2014-04-30 15:06:25 +00:00
parent 99b44bacab
commit fbe7448e5d
10 changed files with 294 additions and 16499 deletions

View File

@ -237,6 +237,20 @@ let isCodeGenOnly = 1, rs = 0, shamt = 0 in {
"sll\t$rd, $rt, 0", [], II_SLL>;
}
// We need the following two pseudo instructions to avoid offset calculation for
// long branches. See the comment in file MipsLongBranch.cpp for detailed
// explanation.
// Expands to: lui $dst, %highest($tgt - $baltgt)
def LONG_BRANCH_LUi64 : PseudoSE<(outs GPR64Opnd:$dst),
(ins brtarget:$tgt, brtarget:$baltgt), []>;
// Expands to: daddiu $dst, $src, %PART($tgt - $baltgt)
// where %PART may be %higher, %hi or %lo, depending on the relocation kind
// that $tgt is annotated with.
def LONG_BRANCH_DADDiu : PseudoSE<(outs GPR64Opnd:$dst),
(ins GPR64Opnd:$src, brtarget:$tgt, brtarget:$baltgt), []>;
// Cavium Octeon cmMIPS instructions
let Predicates = [HasCnMips] in {

View File

@ -148,7 +148,8 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) {
// removing another test for this situation downstream in the
// callchain.
//
if (I->isPseudo() && !Subtarget->inMips16Mode())
if (I->isPseudo() && !Subtarget->inMips16Mode()
&& !isLongBranchPseudo(I->getOpcode()))
llvm_unreachable("Pseudo opcode found in EmitInstruction()");
MCInst TmpInst0;
@ -954,6 +955,13 @@ void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) {
}
}
bool MipsAsmPrinter::isLongBranchPseudo(int Opcode) const {
return (Opcode == Mips::LONG_BRANCH_LUi
|| Opcode == Mips::LONG_BRANCH_ADDiu
|| Opcode == Mips::LONG_BRANCH_LUi64
|| Opcode == Mips::LONG_BRANCH_DADDiu);
}
// Force static initialization.
extern "C" void LLVMInitializeMipsAsmPrinter() {
RegisterAsmPrinter<MipsAsmPrinter> X(TheMipsTarget);

View File

@ -75,6 +75,8 @@ private:
void NaClAlignIndirectJumpTargets(MachineFunction &MF);
bool isLongBranchPseudo(int Opcode) const;
public:
const MipsSubtarget *Subtarget;

View File

@ -9,6 +9,10 @@
//
// This file contains the Mips implementation of the TargetInstrInfo class.
//
// FIXME: We need to override TargetInstrInfo::getInlineAsmLength method in
// order for MipsLongBranch pass to work correctly when the code has inline
// assembly. The returned value doesn't have to be the asm instruction's exact
// size in bytes; MipsLongBranch only expects it to be the correct upper bound.
//===----------------------------------------------------------------------===//
#ifndef MIPSINSTRUCTIONINFO_H

View File

@ -928,6 +928,18 @@ let isPseudo = 1, isCodeGenOnly = 1 in {
def STORE_ACC64 : Store<"", ACC64>;
}
// We need these two pseudo instructions to avoid offset calculation for long
// branches. See the comment in file MipsLongBranch.cpp for detailed
// explanation.
// Expands to: lui $dst, %hi($tgt - $baltgt)
def LONG_BRANCH_LUi : PseudoSE<(outs GPR32Opnd:$dst),
(ins brtarget:$tgt, brtarget:$baltgt), []>;
// Expands to: addiu $dst, $src, %lo($tgt - $baltgt)
def LONG_BRANCH_ADDiu : PseudoSE<(outs GPR32Opnd:$dst),
(ins GPR32Opnd:$src, brtarget:$tgt, brtarget:$baltgt), []>;
//===----------------------------------------------------------------------===//
// Instruction definition
//===----------------------------------------------------------------------===//

View File

@ -10,10 +10,7 @@
// This pass expands a branch or jump instruction into a long branch if its
// offset is too large to fit into its immediate field.
//
// FIXME:
// 1. Fix pc-region jump instructions which cross 256MB segment boundaries.
// 2. If program has inline assembly statements whose size cannot be
// determined accurately, load branch target addresses from the GOT.
// FIXME: Fix pc-region jump instructions which cross 256MB segment boundaries.
//===----------------------------------------------------------------------===//
#include "Mips.h"
@ -267,20 +264,14 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {
LongBrMBB->addSuccessor(BalTgtMBB);
BalTgtMBB->addSuccessor(TgtMBB);
int64_t TgtAddress = MBBInfos[TgtMBB->getNumber()].Address;
unsigned BalTgtMBBSize = 5;
int64_t Offset = TgtAddress - (I.Address + I.Size - BalTgtMBBSize * 4);
int64_t Lo = SignExtend64<16>(Offset & 0xffff);
int64_t Hi = SignExtend64<16>(((Offset + 0x8000) >> 16) & 0xffff);
if (ABI != MipsSubtarget::N64) {
// $longbr:
// addiu $sp, $sp, -8
// sw $ra, 0($sp)
// bal $baltgt
// lui $at, %hi($tgt - $baltgt)
// $baltgt:
// bal $baltgt
// addiu $at, $at, %lo($tgt - $baltgt)
// $baltgt:
// addu $at, $ra, $at
// lw $ra, 0($sp)
// jr $at
@ -295,14 +286,31 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SW)).addReg(Mips::RA)
.addReg(Mips::SP).addImm(0);
// LUi and ADDiu instructions create 32-bit offset of the target basic
// block from the target of BAL instruction. We cannot use immediate
// value for this offset because it cannot be determined accurately when
// the program has inline assembly statements. We therefore use the
// relocation expressions %hi($tgt-$baltgt) and %lo($tgt-$baltgt) which
// are resolved during the fixup, so the values will always be correct.
//
// Since we cannot create %hi($tgt-$baltgt) and %lo($tgt-$baltgt)
// expressions at this point (it is possible only at the MC layer),
// we replace LUi and ADDiu with pseudo instructions
// LONG_BRANCH_LUi and LONG_BRANCH_ADDiu, and add both basic
// blocks as operands to these instructions. When lowering these pseudo
// instructions to LUi and ADDiu in the MC layer, we will create
// %hi($tgt-$baltgt) and %lo($tgt-$baltgt) expressions and add them as
// operands to lowered instructions.
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_LUi), Mips::AT)
.addMBB(TgtMBB).addMBB(BalTgtMBB);
MIBundleBuilder(*LongBrMBB, Pos)
.append(BuildMI(*MF, DL, TII->get(Mips::BAL_BR)).addMBB(BalTgtMBB))
.append(BuildMI(*MF, DL, TII->get(Mips::LUi), Mips::AT).addImm(Hi));
.append(BuildMI(*MF, DL, TII->get(Mips::LONG_BRANCH_ADDiu), Mips::AT)
.addReg(Mips::AT).addMBB(TgtMBB).addMBB(BalTgtMBB));
Pos = BalTgtMBB->begin();
BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::AT)
.addReg(Mips::AT).addImm(Lo);
BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDu), Mips::AT)
.addReg(Mips::RA).addReg(Mips::AT);
BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LW), Mips::RA)
@ -320,10 +328,10 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {
// daddiu $at, $at, %higher($tgt - $baltgt)
// dsll $at, $at, 16
// daddiu $at, $at, %hi($tgt - $baltgt)
// bal $baltgt
// dsll $at, $at, 16
// $baltgt:
// bal $baltgt
// daddiu $at, $at, %lo($tgt - $baltgt)
// $baltgt:
// daddu $at, $ra, $at
// ld $ra, 0($sp)
// jr64 $at
@ -331,9 +339,10 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {
// $fallthrough:
//
int64_t Higher = SignExtend64<16>(((Offset + 0x80008000) >> 32) & 0xffff);
int64_t Highest =
SignExtend64<16>(((Offset + 0x800080008000LL) >> 48) & 0xffff);
// TODO: %highest and %higher can have non-zero values only when the
// offset is greater than 4GB, which is highly unlikely. Replace
// them (and the following instructon that shifts $at by 16) with the
// instruction that sets $at to zero.
Pos = LongBrMBB->begin();
@ -341,24 +350,28 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {
.addReg(Mips::SP_64).addImm(-16);
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SD)).addReg(Mips::RA_64)
.addReg(Mips::SP_64).addImm(0);
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LUi64), Mips::AT_64)
.addImm(Highest);
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::AT_64)
.addReg(Mips::AT_64).addImm(Higher);
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_LUi64),
Mips::AT_64).addMBB(TgtMBB).addMBB(BalTgtMBB);
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_DADDiu),
Mips::AT_64).addReg(Mips::AT_64).addMBB(TgtMBB, MipsII::MO_HIGHER)
.addMBB(BalTgtMBB);
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DSLL), Mips::AT_64)
.addReg(Mips::AT_64).addImm(16);
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_DADDiu),
Mips::AT_64).addReg(Mips::AT_64).addMBB(TgtMBB, MipsII::MO_ABS_HI)
.addMBB(BalTgtMBB);
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DSLL), Mips::AT_64)
.addReg(Mips::AT_64).addImm(16);
BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::AT_64)
.addReg(Mips::AT_64).addImm(Hi);
MIBundleBuilder(*LongBrMBB, Pos)
.append(BuildMI(*MF, DL, TII->get(Mips::BAL_BR)).addMBB(BalTgtMBB))
.append(BuildMI(*MF, DL, TII->get(Mips::DSLL), Mips::AT_64)
.addReg(Mips::AT_64).addImm(16));
.append(BuildMI(*MF, DL, TII->get(Mips::LONG_BRANCH_DADDiu),
Mips::AT_64).addReg(Mips::AT_64)
.addMBB(TgtMBB, MipsII::MO_ABS_LO)
.addMBB(BalTgtMBB));
Pos = BalTgtMBB->begin();
BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::AT_64)
.addReg(Mips::AT_64).addImm(Lo);
BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::DADDu), Mips::AT_64)
.addReg(Mips::RA_64).addReg(Mips::AT_64);
BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LD), Mips::RA_64)
@ -370,8 +383,7 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {
.addReg(Mips::SP_64).addImm(16));
}
assert(BalTgtMBBSize == BalTgtMBB->size());
assert(LongBrMBB->size() + BalTgtMBBSize == LongBranchSeqSize);
assert(LongBrMBB->size() + BalTgtMBB->size() == LongBranchSeqSize);
} else {
// $longbr:
// j $tgt

View File

@ -151,7 +151,82 @@ MCOperand MipsMCInstLower::LowerOperand(const MachineOperand &MO,
return MCOperand();
}
MCOperand MipsMCInstLower::createSub(MachineBasicBlock *BB1,
MachineBasicBlock *BB2,
MCSymbolRefExpr::VariantKind Kind) const {
const MCSymbolRefExpr *Sym1 = MCSymbolRefExpr::Create(BB1->getSymbol(), *Ctx);
const MCSymbolRefExpr *Sym2 = MCSymbolRefExpr::Create(BB2->getSymbol(), *Ctx);
const MCBinaryExpr *Sub = MCBinaryExpr::CreateSub(Sym1, Sym2, *Ctx);
return MCOperand::CreateExpr(MipsMCExpr::Create(Kind, Sub, *Ctx));
}
void MipsMCInstLower::
lowerLongBranchLUi(const MachineInstr *MI, MCInst &OutMI, int Opcode,
MCSymbolRefExpr::VariantKind Kind) const {
OutMI.setOpcode(Opcode);
// Lower register operand.
OutMI.addOperand(LowerOperand(MI->getOperand(0)));
// Create %hi($tgt-$baltgt) or %highest($tgt-$baltgt).
OutMI.addOperand(createSub(MI->getOperand(1).getMBB(),
MI->getOperand(2).getMBB(), Kind));
}
void MipsMCInstLower::
lowerLongBranchADDiu(const MachineInstr *MI, MCInst &OutMI, int Opcode,
MCSymbolRefExpr::VariantKind Kind) const {
OutMI.setOpcode(Opcode);
// Lower two register operands.
for (unsigned I = 0, E = 2; I != E; ++I) {
const MachineOperand &MO = MI->getOperand(I);
OutMI.addOperand(LowerOperand(MO));
}
// Create %lo($tgt-$baltgt), %hi($tgt-$baltgt) or %higher($tgt-$baltgt).
OutMI.addOperand(createSub(MI->getOperand(2).getMBB(),
MI->getOperand(3).getMBB(), Kind));
}
bool MipsMCInstLower::lowerLongBranch(const MachineInstr *MI,
MCInst &OutMI) const {
switch (MI->getOpcode()) {
default:
return false;
case Mips::LONG_BRANCH_LUi:
lowerLongBranchLUi(MI, OutMI, Mips::LUi, MCSymbolRefExpr::VK_Mips_ABS_HI);
return true;
case Mips::LONG_BRANCH_LUi64:
lowerLongBranchLUi(MI, OutMI, Mips::LUi64,
MCSymbolRefExpr::VK_Mips_HIGHEST);
return true;
case Mips::LONG_BRANCH_ADDiu:
lowerLongBranchADDiu(MI, OutMI, Mips::ADDiu,
MCSymbolRefExpr::VK_Mips_ABS_LO);
return true;
case Mips::LONG_BRANCH_DADDiu:
unsigned TargetFlags = MI->getOperand(2).getTargetFlags();
if (TargetFlags == MipsII::MO_HIGHER)
lowerLongBranchADDiu(MI, OutMI, Mips::DADDiu,
MCSymbolRefExpr::VK_Mips_HIGHER);
else if (TargetFlags == MipsII::MO_ABS_HI)
lowerLongBranchADDiu(MI, OutMI, Mips::DADDiu,
MCSymbolRefExpr::VK_Mips_ABS_HI);
else if (TargetFlags == MipsII::MO_ABS_LO)
lowerLongBranchADDiu(MI, OutMI, Mips::DADDiu,
MCSymbolRefExpr::VK_Mips_ABS_LO);
else
report_fatal_error("Unexpected flags for LONG_BRANCH_DADDiu");
return true;
}
}
void MipsMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
if (lowerLongBranch(MI, OutMI))
return;
OutMI.setOpcode(MI->getOpcode());
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {

View File

@ -9,6 +9,7 @@
#ifndef MIPSMCINSTLOWER_H
#define MIPSMCINSTLOWER_H
#include "MCTargetDesc/MipsMCExpr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/Support/Compiler.h"
@ -36,6 +37,14 @@ public:
private:
MCOperand LowerSymbolOperand(const MachineOperand &MO,
MachineOperandType MOTy, unsigned Offset) const;
MCOperand createSub(MachineBasicBlock *BB1, MachineBasicBlock *BB2,
MCSymbolRefExpr::VariantKind Kind) const;
void lowerLongBranchLUi(const MachineInstr *MI, MCInst &OutMI,
int Opcode, MCSymbolRefExpr::VariantKind Kind) const;
void lowerLongBranchADDiu(const MachineInstr *MI, MCInst &OutMI,
int Opcode,
MCSymbolRefExpr::VariantKind Kind) const;
bool lowerLongBranch(const MachineInstr *MI, MCInst &OutMI) const;
};
}

View File

@ -1,36 +1,132 @@
; RUN: llc -march=mipsel -force-mips-long-branch -disable-mips-delay-filler < %s | FileCheck %s -check-prefix=O32
; RUN: llc -march=mips64el -mcpu=mips4 -mattr=n64 -force-mips-long-branch -disable-mips-delay-filler < %s | FileCheck %s -check-prefix=N64
; RUN: llc -march=mips64el -mcpu=mips64 -mattr=n64 -force-mips-long-branch -disable-mips-delay-filler < %s | FileCheck %s -check-prefix=N64
; RUN: llc -march=mipsel < %s | FileCheck %s
; RUN: llc -march=mipsel -force-mips-long-branch -O3 < %s \
; RUN: | FileCheck %s -check-prefix=O32
; RUN: llc -march=mips64el -mcpu=mips4 -mattr=n64 -force-mips-long-branch -O3 \
; RUN: < %s | FileCheck %s -check-prefix=N64
; RUN: llc -march=mips64el -mcpu=mips64 -mattr=n64 -force-mips-long-branch -O3 \
; RUN: < %s | FileCheck %s -check-prefix=N64
; RUN: llc -march=mipsel -mcpu=mips32r2 -mattr=micromips \
; RUN: -force-mips-long-branch -O3 < %s | FileCheck %s -check-prefix=MICROMIPS
@g0 = external global i32
define void @foo1(i32 %s) nounwind {
@x = external global i32
define void @test1(i32 %s) {
entry:
; O32: nop
; O32: addiu $sp, $sp, -8
; O32: bal
; O32: lui $1, 0
; O32: addiu $1, $1, {{[0-9]+}}
; N64: nop
; N64: daddiu $sp, $sp, -16
; N64: lui $1, 0
; N64: daddiu $1, $1, 0
; N64: dsll $1, $1, 16
; N64: daddiu $1, $1, 0
; N64: bal
; N64: dsll $1, $1, 16
; N64: daddiu $1, $1, {{[0-9]+}}
%cmp = icmp eq i32 %s, 0
br i1 %cmp, label %end, label %then
%tobool = icmp eq i32 %s, 0
br i1 %tobool, label %if.end, label %if.then
then:
store i32 1, i32* @x, align 4
br label %end
if.then: ; preds = %entry
%0 = load i32* @g0, align 4
%add = add nsw i32 %0, 12
store i32 %add, i32* @g0, align 4
br label %if.end
if.end: ; preds = %entry, %if.then
end:
ret void
}
; First check the normal version (without long branch). beqz jumps to return,
; and fallthrough block stores 1 to global variable.
; CHECK: lui $[[R0:[0-9]+]], %hi(_gp_disp)
; CHECK: addiu $[[R0]], $[[R0]], %lo(_gp_disp)
; CHECK: beqz $4, $[[BB0:BB[0-9_]+]]
; CHECK: addu $[[GP:[0-9]+]], $[[R0]], $25
; CHECK: lw $[[R1:[0-9]+]], %got(x)($[[GP]])
; CHECK: addiu $[[R2:[0-9]+]], $zero, 1
; CHECK: sw $[[R2]], 0($[[R1]])
; CHECK: $[[BB0]]:
; CHECK: jr $ra
; CHECK: nop
; Check the MIPS32 version. Check that branch logic is inverted, so that the
; target of the new branch (bnez) is the fallthrough block of the original
; branch. Check that fallthrough block of the new branch contains long branch
; expansion which at the end indirectly jumps to the target of the original
; branch.
; O32: lui $[[R0:[0-9]+]], %hi(_gp_disp)
; O32: addiu $[[R0]], $[[R0]], %lo(_gp_disp)
; O32: bnez $4, $[[BB0:BB[0-9_]+]]
; O32: addu $[[GP:[0-9]+]], $[[R0]], $25
; Check for long branch expansion:
; O32: addiu $sp, $sp, -8
; O32-NEXT: sw $ra, 0($sp)
; O32-NEXT: lui $1, %hi(($[[BB2:BB[0-9_]+]])-($[[BB1:BB[0-9_]+]]))
; O32-NEXT: bal $[[BB1]]
; O32-NEXT: addiu $1, $1, %lo(($[[BB2]])-($[[BB1]]))
; O32-NEXT: $[[BB1]]:
; O32-NEXT: addu $1, $ra, $1
; O32-NEXT: lw $ra, 0($sp)
; O32-NEXT: jr $1
; O32-NEXT: addiu $sp, $sp, 8
; O32: $[[BB0]]:
; O32: lw $[[R1:[0-9]+]], %got(x)($[[GP]])
; O32: addiu $[[R2:[0-9]+]], $zero, 1
; O32: sw $[[R2]], 0($[[R1]])
; O32: $[[BB2]]:
; O32: jr $ra
; O32: nop
; Check the MIPS64 version.
; N64: lui $[[R0:[0-9]+]], %hi(%neg(%gp_rel(test1)))
; N64: bnez $4, $[[BB0:BB[0-9_]+]]
; N64: daddu $[[R1:[0-9]+]], $[[R0]], $25
; Check for long branch expansion:
; N64: daddiu $sp, $sp, -16
; N64-NEXT: sd $ra, 0($sp)
; N64-NEXT: lui $1, %highest(($[[BB2:BB[0-9_]+]])-($[[BB1:BB[0-9_]+]]))
; N64-NEXT: daddiu $1, $1, %higher(($[[BB2]])-($[[BB1]]))
; N64-NEXT: dsll $1, $1, 16
; N64-NEXT: daddiu $1, $1, %hi(($[[BB2]])-($[[BB1]]))
; N64-NEXT: dsll $1, $1, 16
; N64-NEXT: bal $[[BB1]]
; N64-NEXT: daddiu $1, $1, %lo(($[[BB2]])-($[[BB1]]))
; N64-NEXT: $[[BB1]]:
; N64-NEXT: daddu $1, $ra, $1
; N64-NEXT: ld $ra, 0($sp)
; N64-NEXT: jr $1
; N64-NEXT: daddiu $sp, $sp, 16
; N64: $[[BB0]]:
; N64: daddiu $[[GP:[0-9]+]], $[[R1]], %lo(%neg(%gp_rel(test1)))
; N64: ld $[[R2:[0-9]+]], %got_disp(x)($[[GP]])
; N64: addiu $[[R3:[0-9]+]], $zero, 1
; N64: sw $[[R3]], 0($[[R2]])
; N64: $[[BB2]]:
; N64: jr $ra
; N64: nop
; Check the microMIPS version.
; MICROMIPS: lui $[[R0:[0-9]+]], %hi(_gp_disp)
; MICROMIPS: addiu $[[R0]], $[[R0]], %lo(_gp_disp)
; MICROMIPS: bnez $4, $[[BB0:BB[0-9_]+]]
; MICROMIPS: addu $[[GP:[0-9]+]], $[[R0]], $25
; Check for long branch expansion:
; MICROMIPS: addiu $sp, $sp, -8
; MICROMIPS-NEXT: sw $ra, 0($sp)
; MICROMIPS-NEXT: lui $1, %hi(($[[BB2:BB[0-9_]+]])-($[[BB1:BB[0-9_]+]]))
; MICROMIPS-NEXT: bal $[[BB1]]
; MICROMIPS-NEXT: addiu $1, $1, %lo(($[[BB2]])-($[[BB1]]))
; MICROMIPS-NEXT: $[[BB1]]:
; MICROMIPS-NEXT: addu $1, $ra, $1
; MICROMIPS-NEXT: lw $ra, 0($sp)
; MICROMIPS-NEXT: jr $1
; MICROMIPS-NEXT: addiu $sp, $sp, 8
; MICROMIPS: $[[BB0]]:
; MICROMIPS: lw $[[R1:[0-9]+]], %got(x)($[[GP]])
; MICROMIPS: addiu $[[R2:[0-9]+]], $zero, 1
; MICROMIPS: sw $[[R2]], 0($[[R1]])
; MICROMIPS: $[[BB2]]:
; MICROMIPS: jr $ra
; MICROMIPS: nop
}

File diff suppressed because it is too large Load Diff