diff options
22 files changed, 1412 insertions, 38 deletions
diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 345b081500a..f36a4317b1b 100644 --- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -5136,6 +5136,7 @@ unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) {    // It also applies for registers Rt and Rs of microMIPSr6 jalrc.hb instruction    // and registers Rd and Base for microMIPS lwp instruction    case Mips::JALR_HB: +  case Mips::JALR_HB64:    case Mips::JALRC_HB_MMR6:    case Mips::JALRC_MMR6:      if (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg()) diff --git a/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td b/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td index 59433ba8de2..63356f9d643 100644 --- a/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td +++ b/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td @@ -1713,6 +1713,12 @@ let AddedComplexity = 41 in {  def TAILCALL_MMR6 : TailCall<BC_MMR6, brtarget26_mm>, ISA_MICROMIPS32R6; +def TAILCALLREG_MMR6  : TailCallReg<JRC16_MM, GPR32Opnd>, ISA_MICROMIPS32R6; + +def PseudoIndirectBranch_MMR6 : PseudoIndirectBranchBase<JRC16_MMR6, +                                                         GPR32Opnd>, +                                ISA_MICROMIPS32R6; +  def : MipsPat<(MipsTailCall (iPTR tglobaladdr:$dst)),                (TAILCALL_MMR6 tglobaladdr:$dst)>, ISA_MICROMIPS32R6; diff --git a/llvm/lib/Target/Mips/MicroMipsInstrInfo.td b/llvm/lib/Target/Mips/MicroMipsInstrInfo.td index a0b7e9429aa..20995f23721 100644 --- a/llvm/lib/Target/Mips/MicroMipsInstrInfo.td +++ b/llvm/lib/Target/Mips/MicroMipsInstrInfo.td @@ -1011,6 +1011,12 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in {  def TAILCALL_MM : TailCall<J_MM, jmptarget_mm>, ISA_MIPS1_NOT_32R6_64R6; +def TAILCALLREG_MM  : TailCallReg<JRC16_MM, GPR32Opnd>, +                      ISA_MICROMIPS32_NOT_MIPS32R6; + +def PseudoIndirectBranch_MM : PseudoIndirectBranchBase<JR_MM, GPR32Opnd>, +                              ISA_MICROMIPS32_NOT_MIPS32R6; +  let DecoderNamespace = "MicroMips" in {    def RDHWR_MM : MMRel, R6MMR6Rel, ReadHardware<GPR32Opnd, HWRegsOpnd>,                   RDHWR_FM_MM, ISA_MICROMIPS32_NOT_MIPS32R6; diff --git a/llvm/lib/Target/Mips/Mips.td b/llvm/lib/Target/Mips/Mips.td index 6ceb0557753..f8e739497f4 100644 --- a/llvm/lib/Target/Mips/Mips.td +++ b/llvm/lib/Target/Mips/Mips.td @@ -193,6 +193,10 @@ def FeatureMT : SubtargetFeature<"mt", "HasMT", "true", "Mips MT ASE">;  def FeatureLongCalls : SubtargetFeature<"long-calls", "UseLongCalls", "true",                                          "Disable use of the jal instruction">; +def FeatureUseIndirectJumpsHazard : SubtargetFeature<"use-indirect-jump-hazard", +                                                    "UseIndirectJumpsHazard", +                                                    "true", "Use indirect jump" +                        " guards to prevent certain speculation based attacks">;  //===----------------------------------------------------------------------===//  // Mips processors supported.  //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Mips/Mips32r6InstrInfo.td b/llvm/lib/Target/Mips/Mips32r6InstrInfo.td index 62f045e77fd..9e9e074875d 100644 --- a/llvm/lib/Target/Mips/Mips32r6InstrInfo.td +++ b/llvm/lib/Target/Mips/Mips32r6InstrInfo.td @@ -1036,3 +1036,42 @@ def : MipsPat<(select i32:$cond, immz, i32:$f),                (SELEQZ i32:$f, i32:$cond)>,                ISA_MIPS32R6;  } + +// Pseudo instructions +let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, hasDelaySlot = 1, +    hasExtraSrcRegAllocReq = 1, isCTI = 1, Defs = [AT] in { +  class TailCallRegR6<Instruction JumpInst, Register RT, RegisterOperand RO> : +    PseudoSE<(outs), (ins RO:$rs), [(MipsTailCall RO:$rs)], II_JR>, +    PseudoInstExpansion<(JumpInst RT:$rt, RO:$rs)>; +} + +class PseudoIndirectBranchBaseR6<Instruction JumpInst, Register RT, +                                 RegisterOperand RO> : +    MipsPseudo<(outs), (ins RO:$rs), [(brind RO:$rs)], +               II_IndirectBranchPseudo>, +    PseudoInstExpansion<(JumpInst RT:$rt, RO:$rs)> { +  let isTerminator=1; +  let isBarrier=1; +  let hasDelaySlot = 1; +  let isBranch = 1; +  let isIndirectBranch = 1; +  bit isCTI = 1; +} + + +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, +                            NoIndirectJumpGuards] in { +  def TAILCALLR6REG : TailCallRegR6<JALR, ZERO, GPR32Opnd>, ISA_MIPS32R6; +  def PseudoIndirectBranchR6 : PseudoIndirectBranchBaseR6<JALR, ZERO, +                                                          GPR32Opnd>, +                               ISA_MIPS32R6; +} + +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, +                            UseIndirectJumpsHazard] in { +  def TAILCALLHBR6REG : TailCallReg<JR_HB_R6, GPR32Opnd>, ISA_MIPS32R6; +  def PseudoIndrectHazardBranchR6 : PseudoIndirectBranchBase<JR_HB_R6, +                                                             GPR32Opnd>, +                                    ISA_MIPS32R6; +} + diff --git a/llvm/lib/Target/Mips/Mips64InstrInfo.td b/llvm/lib/Target/Mips/Mips64InstrInfo.td index e008aeafaa2..828dd4f5422 100644 --- a/llvm/lib/Target/Mips/Mips64InstrInfo.td +++ b/llvm/lib/Target/Mips/Mips64InstrInfo.td @@ -240,13 +240,32 @@ let isCodeGenOnly = 1 in {    def BGTZ64 : CBranchZero<"bgtz", brtarget, setgt, GPR64Opnd>, BGEZ_FM<7, 0>;    def BLEZ64 : CBranchZero<"blez", brtarget, setle, GPR64Opnd>, BGEZ_FM<6, 0>;    def BLTZ64 : CBranchZero<"bltz", brtarget, setlt, GPR64Opnd>, BGEZ_FM<1, 0>; -  def JALR64Pseudo : JumpLinkRegPseudo<GPR64Opnd, JALR, RA, GPR32Opnd>; +  let AdditionalPredicates = [NoIndirectJumpGuards] in +    def JALR64Pseudo : JumpLinkRegPseudo<GPR64Opnd, JALR, RA, GPR32Opnd>;  } +let AdditionalPredicates = [NotInMicroMips], +    DecoderNamespace = "Mips64" in { +  def JR_HB64 : JR_HB_DESC<GPR64Opnd>, JR_HB_ENC, ISA_MIPS32_NOT_32R6_64R6; +  def JALR_HB64 : JALR_HB_DESC<GPR64Opnd>, JALR_HB_ENC, ISA_MIPS32R2; +} +def PseudoReturn64 : PseudoReturnBase<GPR64Opnd>; -def TAILCALLREG64 : TailCallReg<GPR64Opnd>; +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, +                            NoIndirectJumpGuards] in { +  def TAILCALLREG64 : TailCallReg<JR64, GPR64Opnd>, ISA_MIPS3_NOT_32R6_64R6, +                      PTR_64; +  def PseudoIndirectBranch64 : PseudoIndirectBranchBase<JR64, GPR64Opnd>, +                               ISA_MIPS3_NOT_32R6_64R6; +} -def PseudoReturn64 : PseudoReturnBase<GPR64Opnd>; -def PseudoIndirectBranch64 : PseudoIndirectBranchBase<GPR64Opnd>; +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, +                            UseIndirectJumpsHazard] in { +  def TAILCALLREGHB64 : TailCallReg<JR_HB64, GPR64Opnd>, +                        ISA_MIPS32R2_NOT_32R6_64R6, PTR_64; +  def PseudoIndirectHazardBranch64 : PseudoIndirectBranchBase<JR_HB64, +                                                              GPR64Opnd>, +                                     ISA_MIPS32R2_NOT_32R6_64R6; +}  /// Multiply and Divide Instructions.  let AdditionalPredicates = [NotInMicroMips] in { @@ -536,6 +555,10 @@ def DMTC2 : MTC3OP<"dmtc2", COP2Opnd, GPR64Opnd, II_DMTC2>, MFC3OP_FM<0x12, 5>,              ISA_MIPS3;  } + +let AdditionalPredicates = [UseIndirectJumpsHazard] in +  def JALRHB64Pseudo : JumpLinkRegPseudo<GPR64Opnd, JALR_HB64, RA_64>; +  //===----------------------------------------------------------------------===//  //  Arbitrary patterns that map to one or more instructions  //===----------------------------------------------------------------------===// @@ -843,7 +866,8 @@ let AdditionalPredicates = [NotInMicroMips] in {    def : MipsInstAlias<"dext $rt, $rs, $pos, $size",                        (DEXTU GPR64Opnd:$rt, GPR64Opnd:$rs, uimm5_plus32:$pos,                               uimm5_plus1:$size), 0>, ISA_MIPS64R2; - +  def : MipsInstAlias<"jalr.hb $rs", (JALR_HB64 RA_64, GPR64Opnd:$rs), 1>, +        ISA_MIPS64;  // Two operand (implicit 0 selector) versions:    def : MipsInstAlias<"dmtc0 $rt, $rd",                        (DMTC0 COP0Opnd:$rd, GPR64Opnd:$rt, 0), 0>; diff --git a/llvm/lib/Target/Mips/Mips64r6InstrInfo.td b/llvm/lib/Target/Mips/Mips64r6InstrInfo.td index 1cd43ee6f1c..da743fbdee4 100644 --- a/llvm/lib/Target/Mips/Mips64r6InstrInfo.td +++ b/llvm/lib/Target/Mips/Mips64r6InstrInfo.td @@ -104,6 +104,16 @@ class JIC64_DESC : JMP_IDX_COMPACT_DESC_BASE<"jic", jmpoffset16, GPR64Opnd,  class LL64_R6_DESC : LL_R6_DESC_BASE<"ll", GPR32Opnd, mem_simm9, II_LL>;  class SC64_R6_DESC : SC_R6_DESC_BASE<"sc", GPR32Opnd, II_SC>; + +class JR_HB64_R6_DESC : JR_HB_DESC_BASE<"jr.hb", GPR64Opnd> { +  bit isBranch = 1; +  bit isIndirectBranch = 1; +  bit hasDelaySlot = 1; +  bit isTerminator=1; +  bit isBarrier=1; +  bit isCTI = 1; +  InstrItinClass Itinerary = II_JR_HB; +}  //===----------------------------------------------------------------------===//  //  // Instruction Definitions @@ -136,6 +146,7 @@ def SCD_R6 : SCD_R6_ENC, SCD_R6_DESC, ISA_MIPS32R6;  let DecoderNamespace = "Mips32r6_64r6_GP64" in {    def SELEQZ64 : SELEQZ_ENC, SELEQZ64_DESC, ISA_MIPS32R6, GPR_64;    def SELNEZ64 : SELNEZ_ENC, SELNEZ64_DESC, ISA_MIPS32R6, GPR_64; +  def JR_HB64_R6 : JR_HB_R6_ENC, JR_HB64_R6_DESC, ISA_MIPS32R6;  }  let AdditionalPredicates = [NotInMicroMips],      DecoderNamespace = "Mips32r6_64r6_PTR64" in { @@ -277,3 +288,22 @@ def : MipsPat<(select (i32 (setne i32:$cond, immz)), immz, i64:$f),  def : MipsPat<(select (i32 (seteq i32:$cond, immz)), immz, i64:$f),                (SELNEZ64 i64:$f, (SLL64_32 i32:$cond))>,                ISA_MIPS64R6; + +// Pseudo instructions + +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, +                            NoIndirectJumpGuards] in { +  def TAILCALL64R6REG : TailCallRegR6<JALR64, ZERO_64, GPR64Opnd>, ISA_MIPS64R6; +  def PseudoIndirectBranch64R6 : PseudoIndirectBranchBaseR6<JALR64, ZERO_64, +                                                            GPR64Opnd>, +                                 ISA_MIPS64R6; +} + +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, +                            UseIndirectJumpsHazard] in { +  def TAILCALLHB64R6REG : TailCallReg<JR_HB64_R6, GPR64Opnd>, +                          ISA_MIPS64R6; +  def PseudoIndrectHazardBranch64R6 : PseudoIndirectBranchBase<JR_HB64_R6, +                                                                 GPR64Opnd>, +                                      ISA_MIPS64R6; +} diff --git a/llvm/lib/Target/Mips/MipsDSPInstrFormats.td b/llvm/lib/Target/Mips/MipsDSPInstrFormats.td index 0ceb1858fb0..2dcefdc789a 100644 --- a/llvm/lib/Target/Mips/MipsDSPInstrFormats.td +++ b/llvm/lib/Target/Mips/MipsDSPInstrFormats.td @@ -53,7 +53,7 @@ class DSPInst<string opstr = "">  class PseudoDSP<dag outs, dag ins, list<dag> pattern,                  InstrItinClass itin = IIPseudo> -    : MipsPseudo<outs, ins, pattern, itin>, PredicateControl { +    : MipsPseudo<outs, ins, pattern, itin> {    let InsnPredicates = [HasDSP];  } diff --git a/llvm/lib/Target/Mips/MipsInstrFormats.td b/llvm/lib/Target/Mips/MipsInstrFormats.td index 817d9b44b9c..516edef0556 100644 --- a/llvm/lib/Target/Mips/MipsInstrFormats.td +++ b/llvm/lib/Target/Mips/MipsInstrFormats.td @@ -128,7 +128,7 @@ class InstSE<dag outs, dag ins, string asmstr, list<dag> pattern,  // Mips Pseudo Instructions Format  class MipsPseudo<dag outs, dag ins, list<dag> pattern,                   InstrItinClass itin = IIPseudo> : -  MipsInst<outs, ins, "", pattern, itin, Pseudo> { +  MipsInst<outs, ins, "", pattern, itin, Pseudo>, PredicateControl {    let isCodeGenOnly = 1;    let isPseudo = 1;  } @@ -136,7 +136,7 @@ class MipsPseudo<dag outs, dag ins, list<dag> pattern,  // Mips32/64 Pseudo Instruction Format  class PseudoSE<dag outs, dag ins, list<dag> pattern,                 InstrItinClass itin = IIPseudo> : -  MipsPseudo<outs, ins, pattern, itin>, PredicateControl { +  MipsPseudo<outs, ins, pattern, itin> {    let EncodingPredicates = [HasStdEnc];  } diff --git a/llvm/lib/Target/Mips/MipsInstrInfo.cpp b/llvm/lib/Target/Mips/MipsInstrInfo.cpp index 51ddc0d44c0..2e30d271e13 100644 --- a/llvm/lib/Target/Mips/MipsInstrInfo.cpp +++ b/llvm/lib/Target/Mips/MipsInstrInfo.cpp @@ -298,7 +298,6 @@ unsigned MipsInstrInfo::getEquivalentCompactForm(      case Mips::JR:      case Mips::PseudoReturn:      case Mips::PseudoIndirectBranch: -    case Mips::TAILCALLREG:        canUseShortMicroMipsCTI = true;        break;      } @@ -377,18 +376,18 @@ unsigned MipsInstrInfo::getEquivalentCompactForm(      // For MIPSR6, the instruction 'jic' can be used for these cases. Some      // tools will accept 'jrc reg' as an alias for 'jic 0, $reg'.      case Mips::JR: +    case Mips::PseudoIndirectBranchR6:      case Mips::PseudoReturn: -    case Mips::PseudoIndirectBranch: -    case Mips::TAILCALLREG: +    case Mips::TAILCALLR6REG:        if (canUseShortMicroMipsCTI)          return Mips::JRC16_MM;        return Mips::JIC;      case Mips::JALRPseudo:        return Mips::JIALC;      case Mips::JR64: +    case Mips::PseudoIndirectBranch64R6:      case Mips::PseudoReturn64: -    case Mips::PseudoIndirectBranch64: -    case Mips::TAILCALLREG64: +    case Mips::TAILCALL64R6REG:        return Mips::JIC64;      case Mips::JALR64Pseudo:        return Mips::JIALC64; @@ -617,6 +616,18 @@ bool MipsInstrInfo::verifyInstruction(const MachineInstr &MI,        return verifyInsExtInstruction(MI, ErrInfo, 0, 32, 32, 64, 32, 64);      case Mips::DEXTU:        return verifyInsExtInstruction(MI, ErrInfo, 32, 64, 0, 32, 32, 64); +    case Mips::TAILCALLREG: +    case Mips::PseudoIndirectBranch: +    case Mips::JR: +    case Mips::JR64: +    case Mips::JALR: +    case Mips::JALR64: +    case Mips::JALRPseudo: +      if (!Subtarget.useIndirectJumpsHazard()) +        return true; + +      ErrInfo = "invalid instruction when using jump guards!"; +      return false;      default:        return true;    } diff --git a/llvm/lib/Target/Mips/MipsInstrInfo.td b/llvm/lib/Target/Mips/MipsInstrInfo.td index 1e87332f11f..3ecf78e6e09 100644 --- a/llvm/lib/Target/Mips/MipsInstrInfo.td +++ b/llvm/lib/Target/Mips/MipsInstrInfo.td @@ -244,7 +244,10 @@ def HasMadd4 : Predicate<"!Subtarget->disableMadd4()">,                 AssemblerPredicate<"!FeatureMadd4">;  def HasMT  : Predicate<"Subtarget->hasMT()">,               AssemblerPredicate<"FeatureMT">; - +def UseIndirectJumpsHazard : Predicate<"Subtarget->useIndirectJumpsHazard()">, +                            AssemblerPredicate<"FeatureUseIndirectJumpsHazard">; +def NoIndirectJumpGuards : Predicate<"!Subtarget->useIndirectJumpsHazard()">, +                           AssemblerPredicate<"!FeatureUseIndirectJumpsHazard">;  //===----------------------------------------------------------------------===//  // Mips GPR size adjectives.  // They are mutually exclusive. @@ -1542,8 +1545,9 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, hasDelaySlot = 1,      PseudoSE<(outs), (ins calltarget:$target), [], II_J>,      PseudoInstExpansion<(JumpInst Opnd:$target)>; -  class TailCallReg<RegisterOperand RO> : -    PseudoSE<(outs), (ins RO:$rs), [(MipsTailCall RO:$rs)], II_JR>; +  class TailCallReg<Instruction JumpInst, RegisterOperand RO> : +    PseudoSE<(outs), (ins RO:$rs), [(MipsTailCall RO:$rs)], II_JR>, +    PseudoInstExpansion<(JumpInst RO:$rs)>;  }  class BAL_BR_Pseudo<Instruction RealInst> : @@ -2070,7 +2074,7 @@ def B       : UncondBranch<BEQ, brtarget>,                AdditionalRequires<[NotInMicroMips]>;  def JAL  : MMRel, JumpLink<"jal", calltarget>, FJ<3>; -let AdditionalPredicates = [NotInMicroMips] in { +let AdditionalPredicates = [NotInMicroMips, NoIndirectJumpGuards] in {    def JALR : JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM;    def JALRPseudo : JumpLinkRegPseudo<GPR32Opnd, JALR, RA>;  } @@ -2090,24 +2094,28 @@ def BAL_BR : BAL_BR_Pseudo<BGEZAL>;  let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips] in {    def TAILCALL : TailCall<J, jmptarget>;  } - -def TAILCALLREG : TailCallReg<GPR32Opnd>; +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, +                            NoIndirectJumpGuards] in +  def TAILCALLREG : TailCallReg<JR, GPR32Opnd>, ISA_MIPS1_NOT_32R6_64R6;  // Indirect branches are matched as PseudoIndirectBranch/PseudoIndirectBranch64  // then are expanded to JR, JR64, JALR, or JALR64 depending on the ISA. -class PseudoIndirectBranchBase<RegisterOperand RO> : +class PseudoIndirectBranchBase<Instruction JumpInst, RegisterOperand RO> :      MipsPseudo<(outs), (ins RO:$rs), [(brind RO:$rs)], -               II_IndirectBranchPseudo> { +               II_IndirectBranchPseudo>, +    PseudoInstExpansion<(JumpInst RO:$rs)> {    let isTerminator=1;    let isBarrier=1;    let hasDelaySlot = 1;    let isBranch = 1;    let isIndirectBranch = 1;    bit isCTI = 1; -  let Predicates = [NotInMips16Mode];  } -def PseudoIndirectBranch : PseudoIndirectBranchBase<GPR32Opnd>; +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, +                            NoIndirectJumpGuards] in +  def PseudoIndirectBranch : PseudoIndirectBranchBase<JR, GPR32Opnd>, +                             ISA_MIPS1_NOT_32R6_64R6;  // Return instructions are matched as a RetRA instruction, then are expanded  // into PseudoReturn/PseudoReturn64 after register allocation. Finally, @@ -2280,8 +2288,8 @@ class JALR_HB_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> {    list<dag> Pattern = [];  } -class JR_HB_DESC : InstSE<(outs), (ins), "", [], II_JR_HB, FrmJ>, -                   JR_HB_DESC_BASE<"jr.hb", GPR32Opnd> { +class JR_HB_DESC<RegisterOperand RO> : +  InstSE<(outs), (ins), "", [], II_JR_HB, FrmJ>, JR_HB_DESC_BASE<"jr.hb", RO> {    let isBranch=1;    let isIndirectBranch=1;    let hasDelaySlot=1; @@ -2290,8 +2298,9 @@ class JR_HB_DESC : InstSE<(outs), (ins), "", [], II_JR_HB, FrmJ>,    bit isCTI = 1;  } -class JALR_HB_DESC : InstSE<(outs), (ins), "", [], II_JALR_HB, FrmJ>, -                     JALR_HB_DESC_BASE<"jalr.hb", GPR32Opnd> { +class JALR_HB_DESC<RegisterOperand RO> : +  InstSE<(outs), (ins), "", [], II_JALR_HB, FrmJ>, JALR_HB_DESC_BASE<"jalr.hb", +                                                                     RO> {    let isIndirectBranch=1;    let hasDelaySlot=1;    bit isCTI = 1; @@ -2300,8 +2309,19 @@ class JALR_HB_DESC : InstSE<(outs), (ins), "", [], II_JALR_HB, FrmJ>,  class JR_HB_ENC : JR_HB_FM<8>;  class JALR_HB_ENC : JALR_HB_FM<9>; -def JR_HB : JR_HB_DESC, JR_HB_ENC, ISA_MIPS32_NOT_32R6_64R6; -def JALR_HB : JALR_HB_DESC, JALR_HB_ENC, ISA_MIPS32; +def JR_HB : JR_HB_DESC<GPR32Opnd>, JR_HB_ENC, ISA_MIPS32R2_NOT_32R6_64R6; +def JALR_HB : JALR_HB_DESC<GPR32Opnd>, JALR_HB_ENC, ISA_MIPS32; + +let AdditionalPredicates = [NotInMicroMips, UseIndirectJumpsHazard] in +  def JALRHBPseudo : JumpLinkRegPseudo<GPR32Opnd, JALR_HB, RA>; + + +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, +                            UseIndirectJumpsHazard] in { +  def TAILCALLREGHB : TailCallReg<JR_HB, GPR32Opnd>, ISA_MIPS32_NOT_32R6_64R6; +  def PseudoIndirectHazardBranch : PseudoIndirectBranchBase<JR_HB, GPR32Opnd>, +                                   ISA_MIPS32R2_NOT_32R6_64R6; +}  class TLB<string asmstr, InstrItinClass itin = NoItinerary> :    InstSE<(outs), (ins), asmstr, [], itin, FrmOther, asmstr>; @@ -2435,7 +2455,8 @@ def : MipsInstAlias<"j $rs", (JR GPR32Opnd:$rs), 0>;  let Predicates = [NotInMicroMips] in {  def : MipsInstAlias<"jalr $rs", (JALR RA, GPR32Opnd:$rs), 0>;  } -def : MipsInstAlias<"jalr.hb $rs", (JALR_HB RA, GPR32Opnd:$rs), 1>, ISA_MIPS32; +def : MipsInstAlias<"jalr.hb $rs", (JALR_HB RA, GPR32Opnd:$rs), 1>, +      ISA_MIPS32;  def : MipsInstAlias<"neg $rt, $rs",                      (SUB GPR32Opnd:$rt, ZERO, GPR32Opnd:$rs), 1>;  def : MipsInstAlias<"neg $rt", diff --git a/llvm/lib/Target/Mips/MipsLongBranch.cpp b/llvm/lib/Target/Mips/MipsLongBranch.cpp index bbf2050ce1e..e6ecbe9b5f6 100644 --- a/llvm/lib/Target/Mips/MipsLongBranch.cpp +++ b/llvm/lib/Target/Mips/MipsLongBranch.cpp @@ -371,11 +371,12 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {        // In NaCl, modifying the sp is not allowed in branch delay slot.        // For MIPS32R6, we can skip using a delay slot branch. -      if (Subtarget.isTargetNaCl() || Subtarget.hasMips32r6()) +      if (Subtarget.isTargetNaCl() || +          (Subtarget.hasMips32r6() && !Subtarget.useIndirectJumpsHazard()))          BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::SP)            .addReg(Mips::SP).addImm(8); -      if (Subtarget.hasMips32r6()) { +      if (Subtarget.hasMips32r6() && !Subtarget.useIndirectJumpsHazard()) {          const unsigned JICOp =              Subtarget.inMicroMipsMode() ? Mips::JIC_MMR6 : Mips::JIC;          BuildMI(*BalTgtMBB, Pos, DL, TII->get(JICOp)) @@ -383,7 +384,11 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {              .addImm(0);        } else { -        BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::JR)).addReg(Mips::AT); +        unsigned JROp = +            Subtarget.useIndirectJumpsHazard() +                ? (Subtarget.hasMips32r6() ? Mips::JR_HB_R6 : Mips::JR_HB) +                : Mips::JR; +        BuildMI(*BalTgtMBB, Pos, DL, TII->get(JROp)).addReg(Mips::AT);          if (Subtarget.isTargetNaCl()) {            BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::NOP)); @@ -475,7 +480,7 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {        BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LD), Mips::RA_64)          .addReg(Mips::SP_64).addImm(0); -      if (Subtarget.hasMips64r6()) { +      if (Subtarget.hasMips64r6() && !Subtarget.useIndirectJumpsHazard()) {          BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::SP_64)              .addReg(Mips::SP_64)              .addImm(16); @@ -483,7 +488,11 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) {              .addReg(Mips::AT_64)              .addImm(0);        } else { -        BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::JR64)).addReg(Mips::AT_64); +        unsigned JROp = +            Subtarget.useIndirectJumpsHazard() +                ? (Subtarget.hasMips32r6() ? Mips::JR_HB64_R6 : Mips::JR_HB64) +                : Mips::JR64; +        BuildMI(*BalTgtMBB, Pos, DL, TII->get(JROp)).addReg(Mips::AT_64);          BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::SP_64)              .addReg(Mips::SP_64)              .addImm(16); diff --git a/llvm/lib/Target/Mips/MipsSubtarget.cpp b/llvm/lib/Target/Mips/MipsSubtarget.cpp index cbc2ef79e4f..2dc70e2b5b5 100644 --- a/llvm/lib/Target/Mips/MipsSubtarget.cpp +++ b/llvm/lib/Target/Mips/MipsSubtarget.cpp @@ -76,9 +76,10 @@ MipsSubtarget::MipsSubtarget(const Triple &TT, StringRef CPU, StringRef FS,        HasDSPR2(false), HasDSPR3(false), AllowMixed16_32(Mixed16_32 | Mips_Os16),        Os16(Mips_Os16), HasMSA(false), UseTCCInDIV(false), HasSym32(false),        HasEVA(false), DisableMadd4(false), HasMT(false), -      StackAlignOverride(StackAlignOverride), TM(TM), TargetTriple(TT), -      TSInfo(), InstrInfo(MipsInstrInfo::create( -                    initializeSubtargetDependencies(CPU, FS, TM))), +      UseIndirectJumpsHazard(false), StackAlignOverride(StackAlignOverride), +      TM(TM), TargetTriple(TT), TSInfo(), +      InstrInfo( +          MipsInstrInfo::create(initializeSubtargetDependencies(CPU, FS, TM))),        FrameLowering(MipsFrameLowering::create(*this)),        TLInfo(MipsTargetLowering::create(TM, *this)) { @@ -111,6 +112,15 @@ MipsSubtarget::MipsSubtarget(const Triple &TT, StringRef CPU, StringRef FS,    if (hasMips64r6() && InMicroMipsMode)      report_fatal_error("microMIPS64R6 is not supported", false); + +  if (UseIndirectJumpsHazard) { +    if (InMicroMipsMode) +      report_fatal_error( +          "cannot combine indirect jumps with hazard barriers and microMIPS"); +    if (!hasMips32r2()) +      report_fatal_error( +          "indirect jumps with hazard barriers requires MIPS32R2 or later"); +  }    if (hasMips32r6()) {      StringRef ISA = hasMips64r6() ? "MIPS64r6" : "MIPS32r6"; diff --git a/llvm/lib/Target/Mips/MipsSubtarget.h b/llvm/lib/Target/Mips/MipsSubtarget.h index bdf71fce85a..cab824f99a0 100644 --- a/llvm/lib/Target/Mips/MipsSubtarget.h +++ b/llvm/lib/Target/Mips/MipsSubtarget.h @@ -158,6 +158,10 @@ class MipsSubtarget : public MipsGenSubtargetInfo {    // HasMT -- support MT ASE.    bool HasMT; +  // Use hazard variants of the jump register instructions for indirect +  // function calls and jump tables. +  bool UseIndirectJumpsHazard; +    // Disable use of the `jal` instruction.    bool UseLongCalls = false; @@ -278,6 +282,9 @@ public:    bool disableMadd4() const { return DisableMadd4; }    bool hasEVA() const { return HasEVA; }    bool hasMT() const { return HasMT; } +  bool useIndirectJumpsHazard() const { +    return UseIndirectJumpsHazard && hasMips32r2(); +  }    bool useSmallSection() const { return UseSmallSection; }    bool hasStandardEncoding() const { return !inMips16Mode(); } diff --git a/llvm/test/CodeGen/Mips/indirect-jump-hazard/calls.ll b/llvm/test/CodeGen/Mips/indirect-jump-hazard/calls.ll new file mode 100644 index 00000000000..20e89136d87 --- /dev/null +++ b/llvm/test/CodeGen/Mips/indirect-jump-hazard/calls.ll @@ -0,0 +1,188 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc  < %s -mtriple=mips-mti-linux-gnu -relocation-model=static \ +; RUN:   -mips-tail-calls=1 -mcpu=mips32r2 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=MIPS32R2 +; RUN: llc  < %s -mtriple=mips-img-linux-gnu -relocation-model=static \ +; RUN:   -mips-tail-calls=1 -mcpu=mips32r6 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=MIPS32R6 +; RUN: llc  < %s -mtriple=mips64-mti-linux-gnu -relocation-model=static \ +; RUN:   -mips-tail-calls=1 -mcpu=mips64r2 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=MIPS64R2 +; RUN: llc  < %s -mtriple=mips64-img-linux-gnu -relocation-model=static \ +; RUN:   -mips-tail-calls=1 -mcpu=mips64r6 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=MIPS64R6 + +; RUN: llc  < %s -mtriple=mips-mti-linux-gnu -relocation-model=pic \ +; RUN:   -mips-tail-calls=1 -mcpu=mips32r2 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=PIC-MIPS32R2 +; RUN: llc  < %s -mtriple=mips-img-linux-gnu -relocation-model=pic \ +; RUN:   -mips-tail-calls=1 -mcpu=mips32r6 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=PIC-MIPS32R6 +; RUN: llc  < %s -mtriple=mips64-mti-linux-gnu -relocation-model=pic \ +; RUN:   -mips-tail-calls=1 -mcpu=mips64r2 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=PIC-MIPS64R2 +; RUN: llc  < %s -mtriple=mips64-img-linux-gnu -relocation-model=pic \ +; RUN:   -mips-tail-calls=1 -mcpu=mips64r6 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=PIC-MIPS64R6 + +define void @fooNonTail(void (i32)* nocapture %f1) nounwind { +; MIPS32R2-LABEL: fooNonTail: +; MIPS32R2:       # %bb.0: # %entry +; MIPS32R2-NEXT:    addiu $sp, $sp, -24 +; MIPS32R2-NEXT:    sw $ra, 20($sp) # 4-byte Folded Spill +; MIPS32R2-NEXT:    move $1, $4 +; MIPS32R2-NEXT:    move $25, $1 +; MIPS32R2-NEXT:    jalr.hb $25 +; MIPS32R2-NEXT:    addiu $4, $zero, 13 +; MIPS32R2-NEXT:    lw $ra, 20($sp) # 4-byte Folded Reload +; MIPS32R2-NEXT:    jr $ra +; MIPS32R2-NEXT:    addiu $sp, $sp, 24 +; +; MIPS32R6-LABEL: fooNonTail: +; MIPS32R6:       # %bb.0: # %entry +; MIPS32R6-NEXT:    addiu $sp, $sp, -24 +; MIPS32R6-NEXT:    sw $ra, 20($sp) # 4-byte Folded Spill +; MIPS32R6-NEXT:    move $1, $4 +; MIPS32R6-NEXT:    move $25, $1 +; MIPS32R6-NEXT:    jalr.hb $25 +; MIPS32R6-NEXT:    addiu $4, $zero, 13 +; MIPS32R6-NEXT:    lw $ra, 20($sp) # 4-byte Folded Reload +; MIPS32R6-NEXT:    jr $ra +; MIPS32R6-NEXT:    addiu $sp, $sp, 24 +; +; MIPS64R2-LABEL: fooNonTail: +; MIPS64R2:       # %bb.0: # %entry +; MIPS64R2-NEXT:    daddiu $sp, $sp, -16 +; MIPS64R2-NEXT:    sd $ra, 8($sp) # 8-byte Folded Spill +; MIPS64R2-NEXT:    move $1, $4 +; MIPS64R2-NEXT:    move $25, $1 +; MIPS64R2-NEXT:    jalr.hb $25 +; MIPS64R2-NEXT:    daddiu $4, $zero, 13 +; MIPS64R2-NEXT:    ld $ra, 8($sp) # 8-byte Folded Reload +; MIPS64R2-NEXT:    jr $ra +; MIPS64R2-NEXT:    daddiu $sp, $sp, 16 +; +; MIPS64R6-LABEL: fooNonTail: +; MIPS64R6:       # %bb.0: # %entry +; MIPS64R6-NEXT:    daddiu $sp, $sp, -16 +; MIPS64R6-NEXT:    sd $ra, 8($sp) # 8-byte Folded Spill +; MIPS64R6-NEXT:    move $1, $4 +; MIPS64R6-NEXT:    move $25, $1 +; MIPS64R6-NEXT:    jalr.hb $25 +; MIPS64R6-NEXT:    daddiu $4, $zero, 13 +; MIPS64R6-NEXT:    ld $ra, 8($sp) # 8-byte Folded Reload +; MIPS64R6-NEXT:    jr $ra +; MIPS64R6-NEXT:    daddiu $sp, $sp, 16 +; +; PIC-MIPS32R2-LABEL: fooNonTail: +; PIC-MIPS32R2:       # %bb.0: # %entry +; PIC-MIPS32R2-NEXT:    addiu $sp, $sp, -24 +; PIC-MIPS32R2-NEXT:    sw $ra, 20($sp) # 4-byte Folded Spill +; PIC-MIPS32R2-NEXT:    move $1, $4 +; PIC-MIPS32R2-NEXT:    move $25, $1 +; PIC-MIPS32R2-NEXT:    jalr.hb $25 +; PIC-MIPS32R2-NEXT:    addiu $4, $zero, 13 +; PIC-MIPS32R2-NEXT:    lw $ra, 20($sp) # 4-byte Folded Reload +; PIC-MIPS32R2-NEXT:    jr $ra +; PIC-MIPS32R2-NEXT:    addiu $sp, $sp, 24 +; +; PIC-MIPS32R6-LABEL: fooNonTail: +; PIC-MIPS32R6:       # %bb.0: # %entry +; PIC-MIPS32R6-NEXT:    addiu $sp, $sp, -24 +; PIC-MIPS32R6-NEXT:    sw $ra, 20($sp) # 4-byte Folded Spill +; PIC-MIPS32R6-NEXT:    move $1, $4 +; PIC-MIPS32R6-NEXT:    move $25, $1 +; PIC-MIPS32R6-NEXT:    jalr.hb $25 +; PIC-MIPS32R6-NEXT:    addiu $4, $zero, 13 +; PIC-MIPS32R6-NEXT:    lw $ra, 20($sp) # 4-byte Folded Reload +; PIC-MIPS32R6-NEXT:    jr $ra +; PIC-MIPS32R6-NEXT:    addiu $sp, $sp, 24 +; +; PIC-MIPS64R2-LABEL: fooNonTail: +; PIC-MIPS64R2:       # %bb.0: # %entry +; PIC-MIPS64R2-NEXT:    daddiu $sp, $sp, -16 +; PIC-MIPS64R2-NEXT:    sd $ra, 8($sp) # 8-byte Folded Spill +; PIC-MIPS64R2-NEXT:    move $1, $4 +; PIC-MIPS64R2-NEXT:    move $25, $1 +; PIC-MIPS64R2-NEXT:    jalr.hb $25 +; PIC-MIPS64R2-NEXT:    daddiu $4, $zero, 13 +; PIC-MIPS64R2-NEXT:    ld $ra, 8($sp) # 8-byte Folded Reload +; PIC-MIPS64R2-NEXT:    jr $ra +; PIC-MIPS64R2-NEXT:    daddiu $sp, $sp, 16 +; +; PIC-MIPS64R6-LABEL: fooNonTail: +; PIC-MIPS64R6:       # %bb.0: # %entry +; PIC-MIPS64R6-NEXT:    daddiu $sp, $sp, -16 +; PIC-MIPS64R6-NEXT:    sd $ra, 8($sp) # 8-byte Folded Spill +; PIC-MIPS64R6-NEXT:    move $1, $4 +; PIC-MIPS64R6-NEXT:    move $25, $1 +; PIC-MIPS64R6-NEXT:    jalr.hb $25 +; PIC-MIPS64R6-NEXT:    daddiu $4, $zero, 13 +; PIC-MIPS64R6-NEXT:    ld $ra, 8($sp) # 8-byte Folded Reload +; PIC-MIPS64R6-NEXT:    jr $ra +; PIC-MIPS64R6-NEXT:    daddiu $sp, $sp, 16 +entry: +  call void %f1(i32 13) nounwind +  ret void +} + +define i32 @fooTail(i32 (i32)* nocapture %f1) nounwind { +; MIPS32R2-LABEL: fooTail: +; MIPS32R2:       # %bb.0: # %entry +; MIPS32R2-NEXT:    move $1, $4 +; MIPS32R2-NEXT:    move $25, $1 +; MIPS32R2-NEXT:    jr.hb $25 +; MIPS32R2-NEXT:    addiu $4, $zero, 14 +; +; MIPS32R6-LABEL: fooTail: +; MIPS32R6:       # %bb.0: # %entry +; MIPS32R6-NEXT:    move $1, $4 +; MIPS32R6-NEXT:    move $25, $1 +; MIPS32R6-NEXT:    jr.hb $25 +; MIPS32R6-NEXT:    addiu $4, $zero, 14 +; +; MIPS64R2-LABEL: fooTail: +; MIPS64R2:       # %bb.0: # %entry +; MIPS64R2-NEXT:    move $1, $4 +; MIPS64R2-NEXT:    move $25, $1 +; MIPS64R2-NEXT:    jr.hb $25 +; MIPS64R2-NEXT:    daddiu $4, $zero, 14 +; +; MIPS64R6-LABEL: fooTail: +; MIPS64R6:       # %bb.0: # %entry +; MIPS64R6-NEXT:    move $1, $4 +; MIPS64R6-NEXT:    move $25, $1 +; MIPS64R6-NEXT:    jr.hb $25 +; MIPS64R6-NEXT:    daddiu $4, $zero, 14 +; +; PIC-MIPS32R2-LABEL: fooTail: +; PIC-MIPS32R2:       # %bb.0: # %entry +; PIC-MIPS32R2-NEXT:    move $1, $4 +; PIC-MIPS32R2-NEXT:    move $25, $1 +; PIC-MIPS32R2-NEXT:    jr.hb $25 +; PIC-MIPS32R2-NEXT:    addiu $4, $zero, 14 +; +; PIC-MIPS32R6-LABEL: fooTail: +; PIC-MIPS32R6:       # %bb.0: # %entry +; PIC-MIPS32R6-NEXT:    move $1, $4 +; PIC-MIPS32R6-NEXT:    move $25, $1 +; PIC-MIPS32R6-NEXT:    jr.hb $25 +; PIC-MIPS32R6-NEXT:    addiu $4, $zero, 14 +; +; PIC-MIPS64R2-LABEL: fooTail: +; PIC-MIPS64R2:       # %bb.0: # %entry +; PIC-MIPS64R2-NEXT:    move $1, $4 +; PIC-MIPS64R2-NEXT:    move $25, $1 +; PIC-MIPS64R2-NEXT:    jr.hb $25 +; PIC-MIPS64R2-NEXT:    daddiu $4, $zero, 14 +; +; PIC-MIPS64R6-LABEL: fooTail: +; PIC-MIPS64R6:       # %bb.0: # %entry +; PIC-MIPS64R6-NEXT:    move $1, $4 +; PIC-MIPS64R6-NEXT:    move $25, $1 +; PIC-MIPS64R6-NEXT:    jr.hb $25 +; PIC-MIPS64R6-NEXT:    daddiu $4, $zero, 14 +entry: +   %0 = tail call i32 %f1(i32 14) nounwind +   ret i32 %0 +} diff --git a/llvm/test/CodeGen/Mips/indirect-jump-hazard/guards-verify-call.mir b/llvm/test/CodeGen/Mips/indirect-jump-hazard/guards-verify-call.mir new file mode 100644 index 00000000000..9298d9418da --- /dev/null +++ b/llvm/test/CodeGen/Mips/indirect-jump-hazard/guards-verify-call.mir @@ -0,0 +1,58 @@ +# RUN: not llc -mtriple=mips-mti-linux-gnu -mcpu=mips32r2 %s \ +# RUN:         -start-after=expand-isel-pseudos -stop-after=expand-isel-pseudos \ +# RUN:         -verify-machineinstrs -mattr=+use-indirect-jump-hazard -o - 2>&1 \ +# RUN:   | FileCheck %s + +# Test that calls are checked when using indirect jumps guards (hazard variant). + +# CHECK: Bad machine code: invalid instruction when using jump guards! +--- | +  define i32 @fooTail(i32 (i32)* nocapture %f1) { +  entry: +    %0 = tail call i32 %f1(i32 14) +    ret i32 %0 +  } +... +--- +name:            fooTail +alignment:       2 +exposesReturnsTwice: false +legalized:       false +regBankSelected: false +selected:        false +tracksRegLiveness: true +registers: +  - { id: 0, class: gpr32, preferred-register: '' } +  - { id: 1, class: gpr32, preferred-register: '' } +liveins: +  - { reg: '$a0', virtual-reg: '%0' } +frameInfo: +  isFrameAddressTaken: false +  isReturnAddressTaken: false +  hasStackMap:     false +  hasPatchPoint:   false +  stackSize:       0 +  offsetAdjustment: 0 +  maxAlignment:    1 +  adjustsStack:    false +  hasCalls:        false +  stackProtector:  '' +  maxCallFrameSize: 4294967295 +  hasOpaqueSPAdjustment: false +  hasVAStart:      false +  hasMustTailInVarArgFunc: false +  savePoint:       '' +  restorePoint:    '' +fixedStack: +stack: +constants: +body:             | +  bb.0.entry: +    liveins: $a0 + +    %0:gpr32 = COPY $a0 +    %1:gpr32 = ADDiu $zero, 14 +    $a0 = COPY %1 +    TAILCALLREG %0, csr_o32, implicit-def dead $at, implicit $a0 + +... diff --git a/llvm/test/CodeGen/Mips/indirect-jump-hazard/guards-verify-tailcall.mir b/llvm/test/CodeGen/Mips/indirect-jump-hazard/guards-verify-tailcall.mir new file mode 100644 index 00000000000..42ce1236253 --- /dev/null +++ b/llvm/test/CodeGen/Mips/indirect-jump-hazard/guards-verify-tailcall.mir @@ -0,0 +1,59 @@ +# RUN: not llc -mtriple=mips-mti-linux-gnu -mcpu=mips32r2 %s \ +# RUN:         -start-after=expand-isel-pseudos -stop-after=expand-isel-pseudos \ +# RUN:         -verify-machineinstrs -mattr=+use-indirect-jump-hazard -o - 2>&1 \ +# RUN:   | FileCheck %s + +# That that tail calls are checked when using indirect jump guards (hazard variant). + +# CHECK: Bad machine code: invalid instruction when using jump guards! +--- | +  define i32 @fooTail(i32 (i32)* nocapture %f1) { +  entry: +    %0 = tail call i32 %f1(i32 14) +    ret i32 %0 +  } + +... +--- +name:            fooTail +alignment:       2 +exposesReturnsTwice: false +legalized:       false +regBankSelected: false +selected:        false +tracksRegLiveness: true +registers: +  - { id: 0, class: gpr32, preferred-register: '' } +  - { id: 1, class: gpr32, preferred-register: '' } +liveins: +  - { reg: '$a0', virtual-reg: '%0' } +frameInfo: +  isFrameAddressTaken: false +  isReturnAddressTaken: false +  hasStackMap:     false +  hasPatchPoint:   false +  stackSize:       0 +  offsetAdjustment: 0 +  maxAlignment:    1 +  adjustsStack:    false +  hasCalls:        false +  stackProtector:  '' +  maxCallFrameSize: 4294967295 +  hasOpaqueSPAdjustment: false +  hasVAStart:      false +  hasMustTailInVarArgFunc: false +  savePoint:       '' +  restorePoint:    '' +fixedStack: +stack: +constants: +body:             | +  bb.0.entry: +    liveins: $a0 + +    %0:gpr32 = COPY $a0 +    %1:gpr32 = ADDiu $zero, 14 +    $a0 = COPY %1 +    TAILCALLREG %0, csr_o32, implicit-def dead $at, implicit $a0 + +... diff --git a/llvm/test/CodeGen/Mips/indirect-jump-hazard/jumptables.ll b/llvm/test/CodeGen/Mips/indirect-jump-hazard/jumptables.ll new file mode 100644 index 00000000000..c530dd614ef --- /dev/null +++ b/llvm/test/CodeGen/Mips/indirect-jump-hazard/jumptables.ll @@ -0,0 +1,649 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc  < %s -mtriple=mips-mti-linux-gnu -relocation-model=static \ +; RUN:   -mips-tail-calls=1 -mcpu=mips32r2 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=MIPS32R2 +; RUN: llc  < %s -mtriple=mips-img-linux-gnu -relocation-model=static \ +; RUN:   -mips-tail-calls=1 -mcpu=mips32r6 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=MIPS32R6 +; RUN: llc  < %s -mtriple=mips64-mti-linux-gnu -relocation-model=static \ +; RUN:   -mips-tail-calls=1 -mcpu=mips64r2 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=MIPS64R2 +; RUN: llc  < %s -mtriple=mips64-img-linux-gnu -relocation-model=static \ +; RUN:   -mips-tail-calls=1 -mcpu=mips64r6 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=MIPS64R6 + +; RUN: llc  < %s -mtriple=mips-mti-linux-gnu -relocation-model=pic \ +; RUN:   -mips-tail-calls=1 -mcpu=mips32r2 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=PIC-MIPS32R2 +; RUN: llc  < %s -mtriple=mips-img-linux-gnu -relocation-model=pic \ +; RUN:   -mips-tail-calls=1 -mcpu=mips32r6 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=PIC-MIPS32R6 +; RUN: llc  < %s -mtriple=mips64-mti-linux-gnu -relocation-model=pic \ +; RUN:   -mips-tail-calls=1 -mcpu=mips64r2 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=PIC-MIPS64R2 +; RUN: llc  < %s -mtriple=mips64-img-linux-gnu -relocation-model=pic \ +; RUN:   -mips-tail-calls=1 -mcpu=mips64r6 -mattr=+use-indirect-jump-hazard \ +; RUN:   -verify-machineinstrs | FileCheck %s --check-prefix=PIC-MIPS64R6 + +@.str = private unnamed_addr constant [2 x i8] c"A\00", align 1 +@.str.1 = private unnamed_addr constant [2 x i8] c"B\00", align 1 +@.str.2 = private unnamed_addr constant [2 x i8] c"C\00", align 1 +@.str.3 = private unnamed_addr constant [2 x i8] c"D\00", align 1 +@.str.4 = private unnamed_addr constant [2 x i8] c"E\00", align 1 +@.str.5 = private unnamed_addr constant [2 x i8] c"F\00", align 1 +@.str.6 = private unnamed_addr constant [2 x i8] c"G\00", align 1 +@.str.7 = private unnamed_addr constant [1 x i8] zeroinitializer, align 1 + +define i8* @_Z3fooi(i32 signext %Letter) { +; MIPS32R2-LABEL: _Z3fooi: +; MIPS32R2:       # %bb.0: # %entry +; MIPS32R2-NEXT:    addiu $sp, $sp, -16 +; MIPS32R2-NEXT:    .cfi_def_cfa_offset 16 +; MIPS32R2-NEXT:    sltiu $1, $4, 7 +; MIPS32R2-NEXT:    beqz $1, $BB0_3 +; MIPS32R2-NEXT:    sw $4, 4($sp) +; MIPS32R2-NEXT:  $BB0_1: # %entry +; MIPS32R2-NEXT:    sll $1, $4, 2 +; MIPS32R2-NEXT:    lui $2, %hi($JTI0_0) +; MIPS32R2-NEXT:    addu $1, $1, $2 +; MIPS32R2-NEXT:    lw $1, %lo($JTI0_0)($1) +; MIPS32R2-NEXT:    jr.hb $1 +; MIPS32R2-NEXT:    nop +; MIPS32R2-NEXT:  $BB0_2: # %sw.bb +; MIPS32R2-NEXT:    lui $1, %hi($.str) +; MIPS32R2-NEXT:    addiu $1, $1, %lo($.str) +; MIPS32R2-NEXT:    j $BB0_10 +; MIPS32R2-NEXT:    sw $1, 8($sp) +; MIPS32R2-NEXT:  $BB0_3: # %sw.epilog +; MIPS32R2-NEXT:    lui $1, %hi($.str.7) +; MIPS32R2-NEXT:    addiu $1, $1, %lo($.str.7) +; MIPS32R2-NEXT:    j $BB0_10 +; MIPS32R2-NEXT:    sw $1, 8($sp) +; MIPS32R2-NEXT:  $BB0_4: # %sw.bb1 +; MIPS32R2-NEXT:    lui $1, %hi($.str.1) +; MIPS32R2-NEXT:    addiu $1, $1, %lo($.str.1) +; MIPS32R2-NEXT:    j $BB0_10 +; MIPS32R2-NEXT:    sw $1, 8($sp) +; MIPS32R2-NEXT:  $BB0_5: # %sw.bb2 +; MIPS32R2-NEXT:    lui $1, %hi($.str.2) +; MIPS32R2-NEXT:    addiu $1, $1, %lo($.str.2) +; MIPS32R2-NEXT:    j $BB0_10 +; MIPS32R2-NEXT:    sw $1, 8($sp) +; MIPS32R2-NEXT:  $BB0_6: # %sw.bb3 +; MIPS32R2-NEXT:    lui $1, %hi($.str.3) +; MIPS32R2-NEXT:    addiu $1, $1, %lo($.str.3) +; MIPS32R2-NEXT:    j $BB0_10 +; MIPS32R2-NEXT:    sw $1, 8($sp) +; MIPS32R2-NEXT:  $BB0_7: # %sw.bb4 +; MIPS32R2-NEXT:    lui $1, %hi($.str.4) +; MIPS32R2-NEXT:    addiu $1, $1, %lo($.str.4) +; MIPS32R2-NEXT:    j $BB0_10 +; MIPS32R2-NEXT:    sw $1, 8($sp) +; MIPS32R2-NEXT:  $BB0_8: # %sw.bb5 +; MIPS32R2-NEXT:    lui $1, %hi($.str.5) +; MIPS32R2-NEXT:    addiu $1, $1, %lo($.str.5) +; MIPS32R2-NEXT:    j $BB0_10 +; MIPS32R2-NEXT:    sw $1, 8($sp) +; MIPS32R2-NEXT:  $BB0_9: # %sw.bb6 +; MIPS32R2-NEXT:    lui $1, %hi($.str.6) +; MIPS32R2-NEXT:    addiu $1, $1, %lo($.str.6) +; MIPS32R2-NEXT:    sw $1, 8($sp) +; MIPS32R2-NEXT:  $BB0_10: # %return +; MIPS32R2-NEXT:    lw $2, 8($sp) +; MIPS32R2-NEXT:    jr $ra +; MIPS32R2-NEXT:    addiu $sp, $sp, 16 +; +; MIPS32R6-LABEL: _Z3fooi: +; MIPS32R6:       # %bb.0: # %entry +; MIPS32R6-NEXT:    addiu $sp, $sp, -16 +; MIPS32R6-NEXT:    .cfi_def_cfa_offset 16 +; MIPS32R6-NEXT:    sltiu $1, $4, 7 +; MIPS32R6-NEXT:    beqz $1, $BB0_3 +; MIPS32R6-NEXT:    sw $4, 4($sp) +; MIPS32R6-NEXT:  $BB0_1: # %entry +; MIPS32R6-NEXT:    sll $1, $4, 2 +; MIPS32R6-NEXT:    lui $2, %hi($JTI0_0) +; MIPS32R6-NEXT:    addu $1, $1, $2 +; MIPS32R6-NEXT:    lw $1, %lo($JTI0_0)($1) +; MIPS32R6-NEXT:    jr.hb $1 +; MIPS32R6-NEXT:    nop +; MIPS32R6-NEXT:  $BB0_2: # %sw.bb +; MIPS32R6-NEXT:    lui $1, %hi($.str) +; MIPS32R6-NEXT:    addiu $1, $1, %lo($.str) +; MIPS32R6-NEXT:    j $BB0_10 +; MIPS32R6-NEXT:    sw $1, 8($sp) +; MIPS32R6-NEXT:  $BB0_3: # %sw.epilog +; MIPS32R6-NEXT:    lui $1, %hi($.str.7) +; MIPS32R6-NEXT:    addiu $1, $1, %lo($.str.7) +; MIPS32R6-NEXT:    j $BB0_10 +; MIPS32R6-NEXT:    sw $1, 8($sp) +; MIPS32R6-NEXT:  $BB0_4: # %sw.bb1 +; MIPS32R6-NEXT:    lui $1, %hi($.str.1) +; MIPS32R6-NEXT:    addiu $1, $1, %lo($.str.1) +; MIPS32R6-NEXT:    j $BB0_10 +; MIPS32R6-NEXT:    sw $1, 8($sp) +; MIPS32R6-NEXT:  $BB0_5: # %sw.bb2 +; MIPS32R6-NEXT:    lui $1, %hi($.str.2) +; MIPS32R6-NEXT:    addiu $1, $1, %lo($.str.2) +; MIPS32R6-NEXT:    j $BB0_10 +; MIPS32R6-NEXT:    sw $1, 8($sp) +; MIPS32R6-NEXT:  $BB0_6: # %sw.bb3 +; MIPS32R6-NEXT:    lui $1, %hi($.str.3) +; MIPS32R6-NEXT:    addiu $1, $1, %lo($.str.3) +; MIPS32R6-NEXT:    j $BB0_10 +; MIPS32R6-NEXT:    sw $1, 8($sp) +; MIPS32R6-NEXT:  $BB0_7: # %sw.bb4 +; MIPS32R6-NEXT:    lui $1, %hi($.str.4) +; MIPS32R6-NEXT:    addiu $1, $1, %lo($.str.4) +; MIPS32R6-NEXT:    j $BB0_10 +; MIPS32R6-NEXT:    sw $1, 8($sp) +; MIPS32R6-NEXT:  $BB0_8: # %sw.bb5 +; MIPS32R6-NEXT:    lui $1, %hi($.str.5) +; MIPS32R6-NEXT:    addiu $1, $1, %lo($.str.5) +; MIPS32R6-NEXT:    j $BB0_10 +; MIPS32R6-NEXT:    sw $1, 8($sp) +; MIPS32R6-NEXT:  $BB0_9: # %sw.bb6 +; MIPS32R6-NEXT:    lui $1, %hi($.str.6) +; MIPS32R6-NEXT:    addiu $1, $1, %lo($.str.6) +; MIPS32R6-NEXT:    sw $1, 8($sp) +; MIPS32R6-NEXT:  $BB0_10: # %return +; MIPS32R6-NEXT:    lw $2, 8($sp) +; MIPS32R6-NEXT:    jr $ra +; MIPS32R6-NEXT:    addiu $sp, $sp, 16 +; +; MIPS64R2-LABEL: _Z3fooi: +; MIPS64R2:       # %bb.0: # %entry +; MIPS64R2-NEXT:    daddiu $sp, $sp, -16 +; MIPS64R2-NEXT:    .cfi_def_cfa_offset 16 +; MIPS64R2-NEXT:    sw $4, 4($sp) +; MIPS64R2-NEXT:    lwu $2, 4($sp) +; MIPS64R2-NEXT:    sltiu $1, $2, 7 +; MIPS64R2-NEXT:    beqz $1, .LBB0_3 +; MIPS64R2-NEXT:    nop +; MIPS64R2-NEXT:  .LBB0_1: # %entry +; MIPS64R2-NEXT:    daddiu $1, $zero, 8 +; MIPS64R2-NEXT:    dmult $2, $1 +; MIPS64R2-NEXT:    mflo $1 +; MIPS64R2-NEXT:    lui $2, %highest(.LJTI0_0) +; MIPS64R2-NEXT:    daddiu $2, $2, %higher(.LJTI0_0) +; MIPS64R2-NEXT:    dsll $2, $2, 16 +; MIPS64R2-NEXT:    daddiu $2, $2, %hi(.LJTI0_0) +; MIPS64R2-NEXT:    dsll $2, $2, 16 +; MIPS64R2-NEXT:    daddu $1, $1, $2 +; MIPS64R2-NEXT:    ld $1, %lo(.LJTI0_0)($1) +; MIPS64R2-NEXT:    jr.hb $1 +; MIPS64R2-NEXT:    nop +; MIPS64R2-NEXT:  .LBB0_2: # %sw.bb +; MIPS64R2-NEXT:    lui $1, %highest(.L.str) +; MIPS64R2-NEXT:    daddiu $1, $1, %higher(.L.str) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %hi(.L.str) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %lo(.L.str) +; MIPS64R2-NEXT:    j .LBB0_10 +; MIPS64R2-NEXT:    sd $1, 8($sp) +; MIPS64R2-NEXT:  .LBB0_3: # %sw.epilog +; MIPS64R2-NEXT:    lui $1, %highest(.L.str.7) +; MIPS64R2-NEXT:    daddiu $1, $1, %higher(.L.str.7) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %hi(.L.str.7) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %lo(.L.str.7) +; MIPS64R2-NEXT:    j .LBB0_10 +; MIPS64R2-NEXT:    sd $1, 8($sp) +; MIPS64R2-NEXT:  .LBB0_4: # %sw.bb1 +; MIPS64R2-NEXT:    lui $1, %highest(.L.str.1) +; MIPS64R2-NEXT:    daddiu $1, $1, %higher(.L.str.1) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %hi(.L.str.1) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %lo(.L.str.1) +; MIPS64R2-NEXT:    j .LBB0_10 +; MIPS64R2-NEXT:    sd $1, 8($sp) +; MIPS64R2-NEXT:  .LBB0_5: # %sw.bb2 +; MIPS64R2-NEXT:    lui $1, %highest(.L.str.2) +; MIPS64R2-NEXT:    daddiu $1, $1, %higher(.L.str.2) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %hi(.L.str.2) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %lo(.L.str.2) +; MIPS64R2-NEXT:    j .LBB0_10 +; MIPS64R2-NEXT:    sd $1, 8($sp) +; MIPS64R2-NEXT:  .LBB0_6: # %sw.bb3 +; MIPS64R2-NEXT:    lui $1, %highest(.L.str.3) +; MIPS64R2-NEXT:    daddiu $1, $1, %higher(.L.str.3) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %hi(.L.str.3) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %lo(.L.str.3) +; MIPS64R2-NEXT:    j .LBB0_10 +; MIPS64R2-NEXT:    sd $1, 8($sp) +; MIPS64R2-NEXT:  .LBB0_7: # %sw.bb4 +; MIPS64R2-NEXT:    lui $1, %highest(.L.str.4) +; MIPS64R2-NEXT:    daddiu $1, $1, %higher(.L.str.4) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %hi(.L.str.4) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %lo(.L.str.4) +; MIPS64R2-NEXT:    j .LBB0_10 +; MIPS64R2-NEXT:    sd $1, 8($sp) +; MIPS64R2-NEXT:  .LBB0_8: # %sw.bb5 +; MIPS64R2-NEXT:    lui $1, %highest(.L.str.5) +; MIPS64R2-NEXT:    daddiu $1, $1, %higher(.L.str.5) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %hi(.L.str.5) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %lo(.L.str.5) +; MIPS64R2-NEXT:    j .LBB0_10 +; MIPS64R2-NEXT:    sd $1, 8($sp) +; MIPS64R2-NEXT:  .LBB0_9: # %sw.bb6 +; MIPS64R2-NEXT:    lui $1, %highest(.L.str.6) +; MIPS64R2-NEXT:    daddiu $1, $1, %higher(.L.str.6) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %hi(.L.str.6) +; MIPS64R2-NEXT:    dsll $1, $1, 16 +; MIPS64R2-NEXT:    daddiu $1, $1, %lo(.L.str.6) +; MIPS64R2-NEXT:    sd $1, 8($sp) +; MIPS64R2-NEXT:  .LBB0_10: # %return +; MIPS64R2-NEXT:    ld $2, 8($sp) +; MIPS64R2-NEXT:    jr $ra +; MIPS64R2-NEXT:    daddiu $sp, $sp, 16 +; +; MIPS64R6-LABEL: _Z3fooi: +; MIPS64R6:       # %bb.0: # %entry +; MIPS64R6-NEXT:    daddiu $sp, $sp, -16 +; MIPS64R6-NEXT:    .cfi_def_cfa_offset 16 +; MIPS64R6-NEXT:    sw $4, 4($sp) +; MIPS64R6-NEXT:    lwu $2, 4($sp) +; MIPS64R6-NEXT:    sltiu $1, $2, 7 +; MIPS64R6-NEXT:    beqzc $1, .LBB0_3 +; MIPS64R6-NEXT:  .LBB0_1: # %entry +; MIPS64R6-NEXT:    dsll $1, $2, 3 +; MIPS64R6-NEXT:    lui $2, %highest(.LJTI0_0) +; MIPS64R6-NEXT:    daddiu $2, $2, %higher(.LJTI0_0) +; MIPS64R6-NEXT:    dsll $2, $2, 16 +; MIPS64R6-NEXT:    daddiu $2, $2, %hi(.LJTI0_0) +; MIPS64R6-NEXT:    dsll $2, $2, 16 +; MIPS64R6-NEXT:    daddu $1, $1, $2 +; MIPS64R6-NEXT:    ld $1, %lo(.LJTI0_0)($1) +; MIPS64R6-NEXT:    jr.hb $1 +; MIPS64R6-NEXT:    nop +; MIPS64R6-NEXT:  .LBB0_2: # %sw.bb +; MIPS64R6-NEXT:    lui $1, %highest(.L.str) +; MIPS64R6-NEXT:    daddiu $1, $1, %higher(.L.str) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %hi(.L.str) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %lo(.L.str) +; MIPS64R6-NEXT:    j .LBB0_10 +; MIPS64R6-NEXT:    sd $1, 8($sp) +; MIPS64R6-NEXT:  .LBB0_3: # %sw.epilog +; MIPS64R6-NEXT:    lui $1, %highest(.L.str.7) +; MIPS64R6-NEXT:    daddiu $1, $1, %higher(.L.str.7) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %hi(.L.str.7) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %lo(.L.str.7) +; MIPS64R6-NEXT:    j .LBB0_10 +; MIPS64R6-NEXT:    sd $1, 8($sp) +; MIPS64R6-NEXT:  .LBB0_4: # %sw.bb1 +; MIPS64R6-NEXT:    lui $1, %highest(.L.str.1) +; MIPS64R6-NEXT:    daddiu $1, $1, %higher(.L.str.1) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %hi(.L.str.1) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %lo(.L.str.1) +; MIPS64R6-NEXT:    j .LBB0_10 +; MIPS64R6-NEXT:    sd $1, 8($sp) +; MIPS64R6-NEXT:  .LBB0_5: # %sw.bb2 +; MIPS64R6-NEXT:    lui $1, %highest(.L.str.2) +; MIPS64R6-NEXT:    daddiu $1, $1, %higher(.L.str.2) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %hi(.L.str.2) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %lo(.L.str.2) +; MIPS64R6-NEXT:    j .LBB0_10 +; MIPS64R6-NEXT:    sd $1, 8($sp) +; MIPS64R6-NEXT:  .LBB0_6: # %sw.bb3 +; MIPS64R6-NEXT:    lui $1, %highest(.L.str.3) +; MIPS64R6-NEXT:    daddiu $1, $1, %higher(.L.str.3) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %hi(.L.str.3) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %lo(.L.str.3) +; MIPS64R6-NEXT:    j .LBB0_10 +; MIPS64R6-NEXT:    sd $1, 8($sp) +; MIPS64R6-NEXT:  .LBB0_7: # %sw.bb4 +; MIPS64R6-NEXT:    lui $1, %highest(.L.str.4) +; MIPS64R6-NEXT:    daddiu $1, $1, %higher(.L.str.4) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %hi(.L.str.4) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %lo(.L.str.4) +; MIPS64R6-NEXT:    j .LBB0_10 +; MIPS64R6-NEXT:    sd $1, 8($sp) +; MIPS64R6-NEXT:  .LBB0_8: # %sw.bb5 +; MIPS64R6-NEXT:    lui $1, %highest(.L.str.5) +; MIPS64R6-NEXT:    daddiu $1, $1, %higher(.L.str.5) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %hi(.L.str.5) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %lo(.L.str.5) +; MIPS64R6-NEXT:    j .LBB0_10 +; MIPS64R6-NEXT:    sd $1, 8($sp) +; MIPS64R6-NEXT:  .LBB0_9: # %sw.bb6 +; MIPS64R6-NEXT:    lui $1, %highest(.L.str.6) +; MIPS64R6-NEXT:    daddiu $1, $1, %higher(.L.str.6) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %hi(.L.str.6) +; MIPS64R6-NEXT:    dsll $1, $1, 16 +; MIPS64R6-NEXT:    daddiu $1, $1, %lo(.L.str.6) +; MIPS64R6-NEXT:    sd $1, 8($sp) +; MIPS64R6-NEXT:  .LBB0_10: # %return +; MIPS64R6-NEXT:    ld $2, 8($sp) +; MIPS64R6-NEXT:    jr $ra +; MIPS64R6-NEXT:    daddiu $sp, $sp, 16 +; +; PIC-MIPS32R2-LABEL: _Z3fooi: +; PIC-MIPS32R2:       # %bb.0: # %entry +; PIC-MIPS32R2-NEXT:    lui $2, %hi(_gp_disp) +; PIC-MIPS32R2-NEXT:    addiu $2, $2, %lo(_gp_disp) +; PIC-MIPS32R2-NEXT:    addiu $sp, $sp, -16 +; PIC-MIPS32R2-NEXT:    .cfi_def_cfa_offset 16 +; PIC-MIPS32R2-NEXT:    addu $2, $2, $25 +; PIC-MIPS32R2-NEXT:    sltiu $1, $4, 7 +; PIC-MIPS32R2-NEXT:    beqz $1, $BB0_3 +; PIC-MIPS32R2-NEXT:    sw $4, 4($sp) +; PIC-MIPS32R2-NEXT:  $BB0_1: # %entry +; PIC-MIPS32R2-NEXT:    sll $1, $4, 2 +; PIC-MIPS32R2-NEXT:    lw $3, %got($JTI0_0)($2) +; PIC-MIPS32R2-NEXT:    addu $1, $1, $3 +; PIC-MIPS32R2-NEXT:    lw $1, %lo($JTI0_0)($1) +; PIC-MIPS32R2-NEXT:    addu $1, $1, $2 +; PIC-MIPS32R2-NEXT:    jr.hb $1 +; PIC-MIPS32R2-NEXT:    nop +; PIC-MIPS32R2-NEXT:  $BB0_2: # %sw.bb +; PIC-MIPS32R2-NEXT:    lw $1, %got($.str)($2) +; PIC-MIPS32R2-NEXT:    addiu $1, $1, %lo($.str) +; PIC-MIPS32R2-NEXT:    b $BB0_10 +; PIC-MIPS32R2-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R2-NEXT:  $BB0_3: # %sw.epilog +; PIC-MIPS32R2-NEXT:    lw $1, %got($.str.7)($2) +; PIC-MIPS32R2-NEXT:    addiu $1, $1, %lo($.str.7) +; PIC-MIPS32R2-NEXT:    b $BB0_10 +; PIC-MIPS32R2-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R2-NEXT:  $BB0_4: # %sw.bb1 +; PIC-MIPS32R2-NEXT:    lw $1, %got($.str.1)($2) +; PIC-MIPS32R2-NEXT:    addiu $1, $1, %lo($.str.1) +; PIC-MIPS32R2-NEXT:    b $BB0_10 +; PIC-MIPS32R2-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R2-NEXT:  $BB0_5: # %sw.bb2 +; PIC-MIPS32R2-NEXT:    lw $1, %got($.str.2)($2) +; PIC-MIPS32R2-NEXT:    addiu $1, $1, %lo($.str.2) +; PIC-MIPS32R2-NEXT:    b $BB0_10 +; PIC-MIPS32R2-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R2-NEXT:  $BB0_6: # %sw.bb3 +; PIC-MIPS32R2-NEXT:    lw $1, %got($.str.3)($2) +; PIC-MIPS32R2-NEXT:    addiu $1, $1, %lo($.str.3) +; PIC-MIPS32R2-NEXT:    b $BB0_10 +; PIC-MIPS32R2-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R2-NEXT:  $BB0_7: # %sw.bb4 +; PIC-MIPS32R2-NEXT:    lw $1, %got($.str.4)($2) +; PIC-MIPS32R2-NEXT:    addiu $1, $1, %lo($.str.4) +; PIC-MIPS32R2-NEXT:    b $BB0_10 +; PIC-MIPS32R2-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R2-NEXT:  $BB0_8: # %sw.bb5 +; PIC-MIPS32R2-NEXT:    lw $1, %got($.str.5)($2) +; PIC-MIPS32R2-NEXT:    addiu $1, $1, %lo($.str.5) +; PIC-MIPS32R2-NEXT:    b $BB0_10 +; PIC-MIPS32R2-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R2-NEXT:  $BB0_9: # %sw.bb6 +; PIC-MIPS32R2-NEXT:    lw $1, %got($.str.6)($2) +; PIC-MIPS32R2-NEXT:    addiu $1, $1, %lo($.str.6) +; PIC-MIPS32R2-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R2-NEXT:  $BB0_10: # %return +; PIC-MIPS32R2-NEXT:    lw $2, 8($sp) +; PIC-MIPS32R2-NEXT:    jr $ra +; PIC-MIPS32R2-NEXT:    addiu $sp, $sp, 16 +; +; PIC-MIPS32R6-LABEL: _Z3fooi: +; PIC-MIPS32R6:       # %bb.0: # %entry +; PIC-MIPS32R6-NEXT:    lui $2, %hi(_gp_disp) +; PIC-MIPS32R6-NEXT:    addiu $2, $2, %lo(_gp_disp) +; PIC-MIPS32R6-NEXT:    addiu $sp, $sp, -16 +; PIC-MIPS32R6-NEXT:    .cfi_def_cfa_offset 16 +; PIC-MIPS32R6-NEXT:    addu $2, $2, $25 +; PIC-MIPS32R6-NEXT:    sltiu $1, $4, 7 +; PIC-MIPS32R6-NEXT:    beqz $1, $BB0_3 +; PIC-MIPS32R6-NEXT:    sw $4, 4($sp) +; PIC-MIPS32R6-NEXT:  $BB0_1: # %entry +; PIC-MIPS32R6-NEXT:    sll $1, $4, 2 +; PIC-MIPS32R6-NEXT:    lw $3, %got($JTI0_0)($2) +; PIC-MIPS32R6-NEXT:    addu $1, $1, $3 +; PIC-MIPS32R6-NEXT:    lw $1, %lo($JTI0_0)($1) +; PIC-MIPS32R6-NEXT:    addu $1, $1, $2 +; PIC-MIPS32R6-NEXT:    jr.hb $1 +; PIC-MIPS32R6-NEXT:    nop +; PIC-MIPS32R6-NEXT:  $BB0_2: # %sw.bb +; PIC-MIPS32R6-NEXT:    lw $1, %got($.str)($2) +; PIC-MIPS32R6-NEXT:    addiu $1, $1, %lo($.str) +; PIC-MIPS32R6-NEXT:    b $BB0_10 +; PIC-MIPS32R6-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R6-NEXT:  $BB0_3: # %sw.epilog +; PIC-MIPS32R6-NEXT:    lw $1, %got($.str.7)($2) +; PIC-MIPS32R6-NEXT:    addiu $1, $1, %lo($.str.7) +; PIC-MIPS32R6-NEXT:    b $BB0_10 +; PIC-MIPS32R6-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R6-NEXT:  $BB0_4: # %sw.bb1 +; PIC-MIPS32R6-NEXT:    lw $1, %got($.str.1)($2) +; PIC-MIPS32R6-NEXT:    addiu $1, $1, %lo($.str.1) +; PIC-MIPS32R6-NEXT:    b $BB0_10 +; PIC-MIPS32R6-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R6-NEXT:  $BB0_5: # %sw.bb2 +; PIC-MIPS32R6-NEXT:    lw $1, %got($.str.2)($2) +; PIC-MIPS32R6-NEXT:    addiu $1, $1, %lo($.str.2) +; PIC-MIPS32R6-NEXT:    b $BB0_10 +; PIC-MIPS32R6-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R6-NEXT:  $BB0_6: # %sw.bb3 +; PIC-MIPS32R6-NEXT:    lw $1, %got($.str.3)($2) +; PIC-MIPS32R6-NEXT:    addiu $1, $1, %lo($.str.3) +; PIC-MIPS32R6-NEXT:    b $BB0_10 +; PIC-MIPS32R6-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R6-NEXT:  $BB0_7: # %sw.bb4 +; PIC-MIPS32R6-NEXT:    lw $1, %got($.str.4)($2) +; PIC-MIPS32R6-NEXT:    addiu $1, $1, %lo($.str.4) +; PIC-MIPS32R6-NEXT:    b $BB0_10 +; PIC-MIPS32R6-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R6-NEXT:  $BB0_8: # %sw.bb5 +; PIC-MIPS32R6-NEXT:    lw $1, %got($.str.5)($2) +; PIC-MIPS32R6-NEXT:    addiu $1, $1, %lo($.str.5) +; PIC-MIPS32R6-NEXT:    b $BB0_10 +; PIC-MIPS32R6-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R6-NEXT:  $BB0_9: # %sw.bb6 +; PIC-MIPS32R6-NEXT:    lw $1, %got($.str.6)($2) +; PIC-MIPS32R6-NEXT:    addiu $1, $1, %lo($.str.6) +; PIC-MIPS32R6-NEXT:    sw $1, 8($sp) +; PIC-MIPS32R6-NEXT:  $BB0_10: # %return +; PIC-MIPS32R6-NEXT:    lw $2, 8($sp) +; PIC-MIPS32R6-NEXT:    jr $ra +; PIC-MIPS32R6-NEXT:    addiu $sp, $sp, 16 +; +; PIC-MIPS64R2-LABEL: _Z3fooi: +; PIC-MIPS64R2:       # %bb.0: # %entry +; PIC-MIPS64R2-NEXT:    daddiu $sp, $sp, -16 +; PIC-MIPS64R2-NEXT:    .cfi_def_cfa_offset 16 +; PIC-MIPS64R2-NEXT:    lui $1, %hi(%neg(%gp_rel(_Z3fooi))) +; PIC-MIPS64R2-NEXT:    daddu $1, $1, $25 +; PIC-MIPS64R2-NEXT:    daddiu $2, $1, %lo(%neg(%gp_rel(_Z3fooi))) +; PIC-MIPS64R2-NEXT:    sw $4, 4($sp) +; PIC-MIPS64R2-NEXT:    lwu $3, 4($sp) +; PIC-MIPS64R2-NEXT:    sltiu $1, $3, 7 +; PIC-MIPS64R2-NEXT:    beqz $1, .LBB0_3 +; PIC-MIPS64R2-NEXT:    nop +; PIC-MIPS64R2-NEXT:  .LBB0_1: # %entry +; PIC-MIPS64R2-NEXT:    daddiu $1, $zero, 8 +; PIC-MIPS64R2-NEXT:    dmult $3, $1 +; PIC-MIPS64R2-NEXT:    mflo $1 +; PIC-MIPS64R2-NEXT:    ld $3, %got_page(.LJTI0_0)($2) +; PIC-MIPS64R2-NEXT:    daddu $1, $1, $3 +; PIC-MIPS64R2-NEXT:    ld $1, %got_ofst(.LJTI0_0)($1) +; PIC-MIPS64R2-NEXT:    daddu $1, $1, $2 +; PIC-MIPS64R2-NEXT:    jr.hb $1 +; PIC-MIPS64R2-NEXT:    nop +; PIC-MIPS64R2-NEXT:  .LBB0_2: # %sw.bb +; PIC-MIPS64R2-NEXT:    ld $1, %got_page(.L.str)($2) +; PIC-MIPS64R2-NEXT:    daddiu $1, $1, %got_ofst(.L.str) +; PIC-MIPS64R2-NEXT:    b .LBB0_10 +; PIC-MIPS64R2-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R2-NEXT:  .LBB0_3: # %sw.epilog +; PIC-MIPS64R2-NEXT:    ld $1, %got_page(.L.str.7)($2) +; PIC-MIPS64R2-NEXT:    daddiu $1, $1, %got_ofst(.L.str.7) +; PIC-MIPS64R2-NEXT:    b .LBB0_10 +; PIC-MIPS64R2-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R2-NEXT:  .LBB0_4: # %sw.bb1 +; PIC-MIPS64R2-NEXT:    ld $1, %got_page(.L.str.1)($2) +; PIC-MIPS64R2-NEXT:    daddiu $1, $1, %got_ofst(.L.str.1) +; PIC-MIPS64R2-NEXT:    b .LBB0_10 +; PIC-MIPS64R2-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R2-NEXT:  .LBB0_5: # %sw.bb2 +; PIC-MIPS64R2-NEXT:    ld $1, %got_page(.L.str.2)($2) +; PIC-MIPS64R2-NEXT:    daddiu $1, $1, %got_ofst(.L.str.2) +; PIC-MIPS64R2-NEXT:    b .LBB0_10 +; PIC-MIPS64R2-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R2-NEXT:  .LBB0_6: # %sw.bb3 +; PIC-MIPS64R2-NEXT:    ld $1, %got_page(.L.str.3)($2) +; PIC-MIPS64R2-NEXT:    daddiu $1, $1, %got_ofst(.L.str.3) +; PIC-MIPS64R2-NEXT:    b .LBB0_10 +; PIC-MIPS64R2-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R2-NEXT:  .LBB0_7: # %sw.bb4 +; PIC-MIPS64R2-NEXT:    ld $1, %got_page(.L.str.4)($2) +; PIC-MIPS64R2-NEXT:    daddiu $1, $1, %got_ofst(.L.str.4) +; PIC-MIPS64R2-NEXT:    b .LBB0_10 +; PIC-MIPS64R2-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R2-NEXT:  .LBB0_8: # %sw.bb5 +; PIC-MIPS64R2-NEXT:    ld $1, %got_page(.L.str.5)($2) +; PIC-MIPS64R2-NEXT:    daddiu $1, $1, %got_ofst(.L.str.5) +; PIC-MIPS64R2-NEXT:    b .LBB0_10 +; PIC-MIPS64R2-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R2-NEXT:  .LBB0_9: # %sw.bb6 +; PIC-MIPS64R2-NEXT:    ld $1, %got_page(.L.str.6)($2) +; PIC-MIPS64R2-NEXT:    daddiu $1, $1, %got_ofst(.L.str.6) +; PIC-MIPS64R2-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R2-NEXT:  .LBB0_10: # %return +; PIC-MIPS64R2-NEXT:    ld $2, 8($sp) +; PIC-MIPS64R2-NEXT:    jr $ra +; PIC-MIPS64R2-NEXT:    daddiu $sp, $sp, 16 +; +; PIC-MIPS64R6-LABEL: _Z3fooi: +; PIC-MIPS64R6:       # %bb.0: # %entry +; PIC-MIPS64R6-NEXT:    daddiu $sp, $sp, -16 +; PIC-MIPS64R6-NEXT:    .cfi_def_cfa_offset 16 +; PIC-MIPS64R6-NEXT:    lui $1, %hi(%neg(%gp_rel(_Z3fooi))) +; PIC-MIPS64R6-NEXT:    daddu $1, $1, $25 +; PIC-MIPS64R6-NEXT:    daddiu $2, $1, %lo(%neg(%gp_rel(_Z3fooi))) +; PIC-MIPS64R6-NEXT:    sw $4, 4($sp) +; PIC-MIPS64R6-NEXT:    lwu $3, 4($sp) +; PIC-MIPS64R6-NEXT:    sltiu $1, $3, 7 +; PIC-MIPS64R6-NEXT:    beqzc $1, .LBB0_3 +; PIC-MIPS64R6-NEXT:  .LBB0_1: # %entry +; PIC-MIPS64R6-NEXT:    dsll $1, $3, 3 +; PIC-MIPS64R6-NEXT:    ld $3, %got_page(.LJTI0_0)($2) +; PIC-MIPS64R6-NEXT:    daddu $1, $1, $3 +; PIC-MIPS64R6-NEXT:    ld $1, %got_ofst(.LJTI0_0)($1) +; PIC-MIPS64R6-NEXT:    daddu $1, $1, $2 +; PIC-MIPS64R6-NEXT:    jr.hb $1 +; PIC-MIPS64R6-NEXT:    nop +; PIC-MIPS64R6-NEXT:  .LBB0_2: # %sw.bb +; PIC-MIPS64R6-NEXT:    ld $1, %got_page(.L.str)($2) +; PIC-MIPS64R6-NEXT:    daddiu $1, $1, %got_ofst(.L.str) +; PIC-MIPS64R6-NEXT:    b .LBB0_10 +; PIC-MIPS64R6-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R6-NEXT:  .LBB0_3: # %sw.epilog +; PIC-MIPS64R6-NEXT:    ld $1, %got_page(.L.str.7)($2) +; PIC-MIPS64R6-NEXT:    daddiu $1, $1, %got_ofst(.L.str.7) +; PIC-MIPS64R6-NEXT:    b .LBB0_10 +; PIC-MIPS64R6-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R6-NEXT:  .LBB0_4: # %sw.bb1 +; PIC-MIPS64R6-NEXT:    ld $1, %got_page(.L.str.1)($2) +; PIC-MIPS64R6-NEXT:    daddiu $1, $1, %got_ofst(.L.str.1) +; PIC-MIPS64R6-NEXT:    b .LBB0_10 +; PIC-MIPS64R6-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R6-NEXT:  .LBB0_5: # %sw.bb2 +; PIC-MIPS64R6-NEXT:    ld $1, %got_page(.L.str.2)($2) +; PIC-MIPS64R6-NEXT:    daddiu $1, $1, %got_ofst(.L.str.2) +; PIC-MIPS64R6-NEXT:    b .LBB0_10 +; PIC-MIPS64R6-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R6-NEXT:  .LBB0_6: # %sw.bb3 +; PIC-MIPS64R6-NEXT:    ld $1, %got_page(.L.str.3)($2) +; PIC-MIPS64R6-NEXT:    daddiu $1, $1, %got_ofst(.L.str.3) +; PIC-MIPS64R6-NEXT:    b .LBB0_10 +; PIC-MIPS64R6-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R6-NEXT:  .LBB0_7: # %sw.bb4 +; PIC-MIPS64R6-NEXT:    ld $1, %got_page(.L.str.4)($2) +; PIC-MIPS64R6-NEXT:    daddiu $1, $1, %got_ofst(.L.str.4) +; PIC-MIPS64R6-NEXT:    b .LBB0_10 +; PIC-MIPS64R6-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R6-NEXT:  .LBB0_8: # %sw.bb5 +; PIC-MIPS64R6-NEXT:    ld $1, %got_page(.L.str.5)($2) +; PIC-MIPS64R6-NEXT:    daddiu $1, $1, %got_ofst(.L.str.5) +; PIC-MIPS64R6-NEXT:    b .LBB0_10 +; PIC-MIPS64R6-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R6-NEXT:  .LBB0_9: # %sw.bb6 +; PIC-MIPS64R6-NEXT:    ld $1, %got_page(.L.str.6)($2) +; PIC-MIPS64R6-NEXT:    daddiu $1, $1, %got_ofst(.L.str.6) +; PIC-MIPS64R6-NEXT:    sd $1, 8($sp) +; PIC-MIPS64R6-NEXT:  .LBB0_10: # %return +; PIC-MIPS64R6-NEXT:    ld $2, 8($sp) +; PIC-MIPS64R6-NEXT:    jr $ra +; PIC-MIPS64R6-NEXT:    daddiu $sp, $sp, 16 +entry: +  %retval = alloca i8*, align 8 +  %Letter.addr = alloca i32, align 4 +  store i32 %Letter, i32* %Letter.addr, align 4 +  %0 = load i32, i32* %Letter.addr, align 4 +  switch i32 %0, label %sw.epilog [ +    i32 0, label %sw.bb +    i32 1, label %sw.bb1 +    i32 2, label %sw.bb2 +    i32 3, label %sw.bb3 +    i32 4, label %sw.bb4 +    i32 5, label %sw.bb5 +    i32 6, label %sw.bb6 +  ] + +sw.bb: +  store i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str, i32 0, i32 0), i8** %retval, align 8 +  br label %return + +sw.bb1: +  store i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i32 0, i32 0), i8** %retval, align 8 +  br label %return + +sw.bb2: +  store i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.2, i32 0, i32 0), i8** %retval, align 8 +  br label %return + +sw.bb3: +  store i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, i32 0, i32 0), i8** %retval, align 8 +  br label %return + +sw.bb4: +  store i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.4, i32 0, i32 0), i8** %retval, align 8 +  br label %return + +sw.bb5: +  store i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i32 0, i32 0), i8** %retval, align 8 +  br label %return + +sw.bb6: +  store i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.6, i32 0, i32 0), i8** %retval, align 8 +  br label %return + +sw.epilog: +  store i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.7, i32 0, i32 0), i8** %retval, align 8 +  br label %return + +return: +  %1 = load i8*, i8** %retval, align 8 +  ret i8* %1 +} diff --git a/llvm/test/CodeGen/Mips/indirect-jump-hazard/long-branch.ll b/llvm/test/CodeGen/Mips/indirect-jump-hazard/long-branch.ll new file mode 100644 index 00000000000..fffda991ae4 --- /dev/null +++ b/llvm/test/CodeGen/Mips/indirect-jump-hazard/long-branch.ll @@ -0,0 +1,138 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +;       Except for the NACL version which isn't parsed by update_llc_test_checks.py + +; RUN: llc -mtriple=mipsel-unknown-linux-gnu -force-mips-long-branch -O3 \ +; RUN:   -mcpu=mips32r2 -mattr=+use-indirect-jump-hazard -relocation-model=pic \ +; RUN:   -verify-machineinstrs < %s | FileCheck %s -check-prefix=O32-PIC + +; RUN: llc -mtriple=mipsel-unknown-linux-gnu -mcpu=mips32r6 \ +; RUN:   -force-mips-long-branch -O3 -mattr=+use-indirect-jump-hazard  \ +; RUN:   -relocation-model=pic -verify-machineinstrs < %s \ +; RUN:   | FileCheck %s -check-prefix=O32-R6-PIC + +; RUN: llc -mtriple=mips64el-unknown-linux-gnu -mcpu=mips64r2 -target-abi=n64 \ +; RUN:   -force-mips-long-branch -O3 -relocation-model=pic \ +; RUN:   -mattr=+use-indirect-jump-hazard -verify-machineinstrs \ +; RUN:   < %s | FileCheck %s -check-prefix=MIPS64 + +; RUN: llc -mtriple=mips64el-unknown-linux-gnu -mcpu=mips64r6 -target-abi=n64 \ +; RUN:   -force-mips-long-branch -O3 -mattr=+use-indirect-jump-hazard \ +; RUN:   -relocation-model=pic -verify-machineinstrs < %s \ +; RUN:   | FileCheck %s -check-prefix=N64-R6 + +; Test that the long branches also get changed to their hazard variants. + +@x = external global i32 + +define void @test1(i32 signext %s) { +; O32-PIC-LABEL: test1: +; O32-PIC:       # %bb.0: # %entry +; O32-PIC-NEXT:    lui $2, %hi(_gp_disp) +; O32-PIC-NEXT:    addiu $2, $2, %lo(_gp_disp) +; O32-PIC-NEXT:    bnez $4, $BB0_3 +; O32-PIC-NEXT:    addu $2, $2, $25 +; O32-PIC-NEXT:  # %bb.1: # %entry +; O32-PIC-NEXT:    addiu $sp, $sp, -8 +; O32-PIC-NEXT:    sw $ra, 0($sp) +; O32-PIC-NEXT:    lui $1, %hi(($BB0_4)-($BB0_2)) +; O32-PIC-NEXT:    bal $BB0_2 +; O32-PIC-NEXT:    addiu $1, $1, %lo(($BB0_4)-($BB0_2)) +; O32-PIC-NEXT:  $BB0_2: # %entry +; O32-PIC-NEXT:    addu $1, $ra, $1 +; O32-PIC-NEXT:    lw $ra, 0($sp) +; O32-PIC-NEXT:    jr.hb $1 +; O32-PIC-NEXT:    addiu $sp, $sp, 8 +; O32-PIC-NEXT:  $BB0_3: # %then +; O32-PIC-NEXT:    lw $1, %got(x)($2) +; O32-PIC-NEXT:    addiu $2, $zero, 1 +; O32-PIC-NEXT:    sw $2, 0($1) +; O32-PIC-NEXT:  $BB0_4: # %end +; O32-PIC-NEXT:    jr $ra +; O32-PIC-NEXT:    nop +; +; O32-R6-PIC-LABEL: test1: +; O32-R6-PIC:       # %bb.0: # %entry +; O32-R6-PIC-NEXT:    lui $2, %hi(_gp_disp) +; O32-R6-PIC-NEXT:    addiu $2, $2, %lo(_gp_disp) +; O32-R6-PIC-NEXT:    bnez $4, $BB0_3 +; O32-R6-PIC-NEXT:    addu $2, $2, $25 +; O32-R6-PIC-NEXT:  # %bb.1: # %entry +; O32-R6-PIC-NEXT:    addiu $sp, $sp, -8 +; O32-R6-PIC-NEXT:    sw $ra, 0($sp) +; O32-R6-PIC-NEXT:    lui $1, %hi(($BB0_4)-($BB0_2)) +; O32-R6-PIC-NEXT:    addiu $1, $1, %lo(($BB0_4)-($BB0_2)) +; O32-R6-PIC-NEXT:    balc $BB0_2 +; O32-R6-PIC-NEXT:  $BB0_2: # %entry +; O32-R6-PIC-NEXT:    addu $1, $ra, $1 +; O32-R6-PIC-NEXT:    lw $ra, 0($sp) +; O32-R6-PIC-NEXT:    jr.hb $1 +; O32-R6-PIC-NEXT:    addiu $sp, $sp, 8 +; O32-R6-PIC-NEXT:  $BB0_3: # %then +; O32-R6-PIC-NEXT:    lw $1, %got(x)($2) +; O32-R6-PIC-NEXT:    addiu $2, $zero, 1 +; O32-R6-PIC-NEXT:    sw $2, 0($1) +; O32-R6-PIC-NEXT:  $BB0_4: # %end +; O32-R6-PIC-NEXT:    jrc $ra +; +; MIPS64-LABEL: test1: +; MIPS64:       # %bb.0: # %entry +; MIPS64-NEXT:    lui $1, %hi(%neg(%gp_rel(test1))) +; MIPS64-NEXT:    bnez $4, .LBB0_3 +; MIPS64-NEXT:    daddu $2, $1, $25 +; MIPS64-NEXT:  # %bb.1: # %entry +; MIPS64-NEXT:    daddiu $sp, $sp, -16 +; MIPS64-NEXT:    sd $ra, 0($sp) +; MIPS64-NEXT:    daddiu $1, $zero, %hi(.LBB0_4-.LBB0_2) +; MIPS64-NEXT:    dsll $1, $1, 16 +; MIPS64-NEXT:    bal .LBB0_2 +; MIPS64-NEXT:    daddiu $1, $1, %lo(.LBB0_4-.LBB0_2) +; MIPS64-NEXT:  .LBB0_2: # %entry +; MIPS64-NEXT:    daddu $1, $ra, $1 +; MIPS64-NEXT:    ld $ra, 0($sp) +; MIPS64-NEXT:    jr.hb $1 +; MIPS64-NEXT:    daddiu $sp, $sp, 16 +; MIPS64-NEXT:  .LBB0_3: # %then +; MIPS64-NEXT:    daddiu $1, $2, %lo(%neg(%gp_rel(test1))) +; MIPS64-NEXT:    addiu $2, $zero, 1 +; MIPS64-NEXT:    ld $1, %got_disp(x)($1) +; MIPS64-NEXT:    sw $2, 0($1) +; MIPS64-NEXT:  .LBB0_4: # %end +; MIPS64-NEXT:    jr $ra +; MIPS64-NEXT:    nop +; +; N64-R6-LABEL: test1: +; N64-R6:       # %bb.0: # %entry +; N64-R6-NEXT:    lui $1, %hi(%neg(%gp_rel(test1))) +; N64-R6-NEXT:    bnez $4, .LBB0_3 +; N64-R6-NEXT:    daddu $2, $1, $25 +; N64-R6-NEXT:  # %bb.1: # %entry +; N64-R6-NEXT:    daddiu $sp, $sp, -16 +; N64-R6-NEXT:    sd $ra, 0($sp) +; N64-R6-NEXT:    daddiu $1, $zero, %hi(.LBB0_4-.LBB0_2) +; N64-R6-NEXT:    dsll $1, $1, 16 +; N64-R6-NEXT:    daddiu $1, $1, %lo(.LBB0_4-.LBB0_2) +; N64-R6-NEXT:    balc .LBB0_2 +; N64-R6-NEXT:  .LBB0_2: # %entry +; N64-R6-NEXT:    daddu $1, $ra, $1 +; N64-R6-NEXT:    ld $ra, 0($sp) +; N64-R6-NEXT:    jr.hb $1 +; N64-R6-NEXT:    daddiu $sp, $sp, 16 +; N64-R6-NEXT:  .LBB0_3: # %then +; N64-R6-NEXT:    daddiu $1, $2, %lo(%neg(%gp_rel(test1))) +; N64-R6-NEXT:    addiu $2, $zero, 1 +; N64-R6-NEXT:    ld $1, %got_disp(x)($1) +; N64-R6-NEXT:    sw $2, 0($1) +; N64-R6-NEXT:  .LBB0_4: # %end +; N64-R6-NEXT:    jrc $ra +entry: +  %cmp = icmp eq i32 %s, 0 +  br i1 %cmp, label %end, label %then + +then: +  store i32 1, i32* @x, align 4 +  br label %end + +end: +  ret void + +} diff --git a/llvm/test/CodeGen/Mips/indirect-jump-hazard/long-calls.ll b/llvm/test/CodeGen/Mips/indirect-jump-hazard/long-calls.ll new file mode 100644 index 00000000000..50d8fd6dd1d --- /dev/null +++ b/llvm/test/CodeGen/Mips/indirect-jump-hazard/long-calls.ll @@ -0,0 +1,104 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=mips-unknwon-linux-gnu -mcpu=mips32r2 \ +; RUN:   -mattr=+use-indirect-jump-hazard,+long-calls,+noabicalls %s -o - \ +; RUN:   -verify-machineinstrs | FileCheck -check-prefix=O32 %s + +; RUN: llc -mtriple=mips64-unknown-linux-gnu -mcpu=mips64r2 -target-abi n32 \ +; RUN:   -mattr=+use-indirect-jump-hazard,+long-calls,+noabicalls %s -o - \ +; RUN:   -verify-machineinstrs | FileCheck -check-prefix=N32 %s + +; RUN: llc -mtriple=mips64-unknown-linux-gnu -mcpu=mips64r2 -target-abi n64 \ +; RUN:   -mattr=+use-indirect-jump-hazard,+long-calls,+noabicalls %s -o - \ +; RUN:   -verify-machineinstrs | FileCheck -check-prefix=N64 %s + +declare void @callee() +declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i1) + +@val = internal unnamed_addr global [20 x i32] zeroinitializer, align 4 + +; Test that the long call sequence uses the hazard barrier instruction variant. +define void @caller() { +; O32-LABEL: caller: +; O32:       # %bb.0: +; O32-NEXT:    addiu $sp, $sp, -24 +; O32-NEXT:    .cfi_def_cfa_offset 24 +; O32-NEXT:    sw $ra, 20($sp) # 4-byte Folded Spill +; O32-NEXT:    .cfi_offset 31, -4 +; O32-NEXT:    lui $1, %hi(callee) +; O32-NEXT:    addiu $25, $1, %lo(callee) +; O32-NEXT:    jalr.hb $25 +; O32-NEXT:    nop +; O32-NEXT:    addiu $1, $zero, %lo(memset) +; O32-NEXT:    lui $2, %hi(memset) +; O32-NEXT:    addu $25, $2, $1 +; O32-NEXT:    lui $1, %hi(val) +; O32-NEXT:    addiu $4, $1, %lo(val) +; O32-NEXT:    addiu $5, $zero, 0 +; O32-NEXT:    jalr.hb $25 +; O32-NEXT:    addiu $6, $zero, 80 +; O32-NEXT:    lw $ra, 20($sp) # 4-byte Folded Reload +; O32-NEXT:    jr $ra +; O32-NEXT:    addiu $sp, $sp, 24 +; +; N32-LABEL: caller: +; N32:       # %bb.0: +; N32-NEXT:    addiu $sp, $sp, -16 +; N32-NEXT:    .cfi_def_cfa_offset 16 +; N32-NEXT:    sd $ra, 8($sp) # 8-byte Folded Spill +; N32-NEXT:    .cfi_offset 31, -8 +; N32-NEXT:    lui $1, %hi(callee) +; N32-NEXT:    addiu $25, $1, %lo(callee) +; N32-NEXT:    jalr.hb $25 +; N32-NEXT:    nop +; N32-NEXT:    addiu $1, $zero, %lo(memset) +; N32-NEXT:    lui $2, %hi(memset) +; N32-NEXT:    addu $25, $2, $1 +; N32-NEXT:    lui $1, %hi(val) +; N32-NEXT:    addiu $4, $1, %lo(val) +; N32-NEXT:    daddiu $5, $zero, 0 +; N32-NEXT:    jalr.hb $25 +; N32-NEXT:    daddiu $6, $zero, 80 +; N32-NEXT:    ld $ra, 8($sp) # 8-byte Folded Reload +; N32-NEXT:    jr $ra +; N32-NEXT:    addiu $sp, $sp, 16 +; +; N64-LABEL: caller: +; N64:       # %bb.0: +; N64-NEXT:    daddiu $sp, $sp, -16 +; N64-NEXT:    .cfi_def_cfa_offset 16 +; N64-NEXT:    sd $ra, 8($sp) # 8-byte Folded Spill +; N64-NEXT:    .cfi_offset 31, -8 +; N64-NEXT:    lui $1, %highest(callee) +; N64-NEXT:    daddiu $1, $1, %higher(callee) +; N64-NEXT:    dsll $1, $1, 16 +; N64-NEXT:    daddiu $1, $1, %hi(callee) +; N64-NEXT:    dsll $1, $1, 16 +; N64-NEXT:    daddiu $25, $1, %lo(callee) +; N64-NEXT:    jalr.hb $25 +; N64-NEXT:    nop +; N64-NEXT:    daddiu $1, $zero, %higher(memset) +; N64-NEXT:    lui $2, %highest(memset) +; N64-NEXT:    daddu $1, $2, $1 +; N64-NEXT:    dsll $1, $1, 16 +; N64-NEXT:    lui $2, %hi(memset) +; N64-NEXT:    daddu $1, $1, $2 +; N64-NEXT:    dsll $1, $1, 16 +; N64-NEXT:    daddiu $2, $zero, %lo(memset) +; N64-NEXT:    daddu $25, $1, $2 +; N64-NEXT:    lui $1, %highest(val) +; N64-NEXT:    daddiu $1, $1, %higher(val) +; N64-NEXT:    dsll $1, $1, 16 +; N64-NEXT:    daddiu $1, $1, %hi(val) +; N64-NEXT:    dsll $1, $1, 16 +; N64-NEXT:    daddiu $4, $1, %lo(val) +; N64-NEXT:    daddiu $5, $zero, 0 +; N64-NEXT:    jalr.hb $25 +; N64-NEXT:    daddiu $6, $zero, 80 +; N64-NEXT:    ld $ra, 8($sp) # 8-byte Folded Reload +; N64-NEXT:    jr $ra +; N64-NEXT:    daddiu $sp, $sp, 16 +  call void @callee() +  call void @llvm.memset.p0i8.i32(i8* align 4 bitcast ([20 x i32]* @val to i8*), i8 0, i32 80, i1 false) +  ret  void +} + diff --git a/llvm/test/CodeGen/Mips/indirect-jump-hazard/unsupported-micromips.ll b/llvm/test/CodeGen/Mips/indirect-jump-hazard/unsupported-micromips.ll new file mode 100644 index 00000000000..99612525ae3 --- /dev/null +++ b/llvm/test/CodeGen/Mips/indirect-jump-hazard/unsupported-micromips.ll @@ -0,0 +1,5 @@ +; RUN: not llc -mtriple=mips-unknown-linux -mcpu=mips32r2 -mattr=+micromips,+use-indirect-jump-hazard %s 2>&1 | FileCheck %s + +; Test that microMIPS and indirect jump with hazard barriers is not supported. + +; CHECK: LLVM ERROR: cannot combine indirect jumps with hazard barriers and microMIPS diff --git a/llvm/test/CodeGen/Mips/indirect-jump-hazard/unsupported-mips32.ll b/llvm/test/CodeGen/Mips/indirect-jump-hazard/unsupported-mips32.ll new file mode 100644 index 00000000000..48baedf53ea --- /dev/null +++ b/llvm/test/CodeGen/Mips/indirect-jump-hazard/unsupported-mips32.ll @@ -0,0 +1,5 @@ +; RUN: not llc -mtriple=mips-unknown-linux -mcpu=mips32 -mattr=+use-indirect-jump-hazard %s 2>&1 | FileCheck %s + +; Test that mips32 and indirect jump with hazard barriers is not supported. + +; CHECK: LLVM ERROR: indirect jumps with hazard barriers requires MIPS32R2 or later  | 

