diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Target/Mips/Mips64InstrInfo.td | 14 | ||||
-rw-r--r-- | lib/Target/Mips/MipsAsmPrinter.cpp | 10 | ||||
-rw-r--r-- | lib/Target/Mips/MipsAsmPrinter.h | 2 | ||||
-rw-r--r-- | lib/Target/Mips/MipsInstrInfo.h | 4 | ||||
-rw-r--r-- | lib/Target/Mips/MipsInstrInfo.td | 12 | ||||
-rw-r--r-- | lib/Target/Mips/MipsLongBranch.cpp | 76 | ||||
-rw-r--r-- | lib/Target/Mips/MipsMCInstLower.cpp | 75 | ||||
-rw-r--r-- | lib/Target/Mips/MipsMCInstLower.h | 9 |
8 files changed, 169 insertions, 33 deletions
diff --git a/lib/Target/Mips/Mips64InstrInfo.td b/lib/Target/Mips/Mips64InstrInfo.td index fbdc29bc94..7f895e23f9 100644 --- a/lib/Target/Mips/Mips64InstrInfo.td +++ b/lib/Target/Mips/Mips64InstrInfo.td @@ -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 { diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp index 6d3a4f4a24..626657e9df 100644 --- a/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/lib/Target/Mips/MipsAsmPrinter.cpp @@ -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); diff --git a/lib/Target/Mips/MipsAsmPrinter.h b/lib/Target/Mips/MipsAsmPrinter.h index ce11d1ec3b..e82b145925 100644 --- a/lib/Target/Mips/MipsAsmPrinter.h +++ b/lib/Target/Mips/MipsAsmPrinter.h @@ -75,6 +75,8 @@ private: void NaClAlignIndirectJumpTargets(MachineFunction &MF); + bool isLongBranchPseudo(int Opcode) const; + public: const MipsSubtarget *Subtarget; diff --git a/lib/Target/Mips/MipsInstrInfo.h b/lib/Target/Mips/MipsInstrInfo.h index 560a793cea..742193f712 100644 --- a/lib/Target/Mips/MipsInstrInfo.h +++ b/lib/Target/Mips/MipsInstrInfo.h @@ -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 diff --git a/lib/Target/Mips/MipsInstrInfo.td b/lib/Target/Mips/MipsInstrInfo.td index 9899cb4261..3910040228 100644 --- a/lib/Target/Mips/MipsInstrInfo.td +++ b/lib/Target/Mips/MipsInstrInfo.td @@ -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 //===----------------------------------------------------------------------===// diff --git a/lib/Target/Mips/MipsLongBranch.cpp b/lib/Target/Mips/MipsLongBranch.cpp index a90a3e135c..a8fd39176e 100644 --- a/lib/Target/Mips/MipsLongBranch.cpp +++ b/lib/Target/Mips/MipsLongBranch.cpp @@ -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 diff --git a/lib/Target/Mips/MipsMCInstLower.cpp b/lib/Target/Mips/MipsMCInstLower.cpp index 7c9a9ed831..85f7867466 100644 --- a/lib/Target/Mips/MipsMCInstLower.cpp +++ b/lib/Target/Mips/MipsMCInstLower.cpp @@ -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) { diff --git a/lib/Target/Mips/MipsMCInstLower.h b/lib/Target/Mips/MipsMCInstLower.h index 4570bd9099..6971f49ff2 100644 --- a/lib/Target/Mips/MipsMCInstLower.h +++ b/lib/Target/Mips/MipsMCInstLower.h @@ -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; }; } |