diff options
22 files changed, 1421 insertions, 38 deletions
diff --git a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 345b081500a4..f36a4317b1b9 100644 --- a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/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/lib/Target/Mips/MicroMips32r6InstrInfo.td b/lib/Target/Mips/MicroMips32r6InstrInfo.td index 3ff3f07654d9..326897dc5c63 100644 --- a/lib/Target/Mips/MicroMips32r6InstrInfo.td +++ b/lib/Target/Mips/MicroMips32r6InstrInfo.td @@ -1886,6 +1886,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/lib/Target/Mips/MicroMipsInstrInfo.td b/lib/Target/Mips/MicroMipsInstrInfo.td index 64fe55e9776b..1fef51fd69d0 100644 --- a/lib/Target/Mips/MicroMipsInstrInfo.td +++ b/lib/Target/Mips/MicroMipsInstrInfo.td @@ -1003,6 +1003,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/lib/Target/Mips/Mips.td b/lib/Target/Mips/Mips.td index 6ceb05577538..f8e739497f4c 100644 --- a/lib/Target/Mips/Mips.td +++ b/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/lib/Target/Mips/Mips32r6InstrInfo.td b/lib/Target/Mips/Mips32r6InstrInfo.td index 62f045e77fdb..9e9e074875d0 100644 --- a/lib/Target/Mips/Mips32r6InstrInfo.td +++ b/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/lib/Target/Mips/Mips64InstrInfo.td b/lib/Target/Mips/Mips64InstrInfo.td index e008aeafaa2b..828dd4f54223 100644 --- a/lib/Target/Mips/Mips64InstrInfo.td +++ b/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/lib/Target/Mips/Mips64r6InstrInfo.td b/lib/Target/Mips/Mips64r6InstrInfo.td index 1cd43ee6f1c3..da743fbdee45 100644 --- a/lib/Target/Mips/Mips64r6InstrInfo.td +++ b/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/lib/Target/Mips/MipsDSPInstrFormats.td b/lib/Target/Mips/MipsDSPInstrFormats.td index 0ceb1858fb09..2dcefdc789a5 100644 --- a/lib/Target/Mips/MipsDSPInstrFormats.td +++ b/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/lib/Target/Mips/MipsInstrFormats.td b/lib/Target/Mips/MipsInstrFormats.td index 817d9b44b9c2..516edef0556c 100644 --- a/lib/Target/Mips/MipsInstrFormats.td +++ b/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/lib/Target/Mips/MipsInstrInfo.cpp b/lib/Target/Mips/MipsInstrInfo.cpp index 51ddc0d44c00..2e30d271e130 100644 --- a/lib/Target/Mips/MipsInstrInfo.cpp +++ b/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/lib/Target/Mips/MipsInstrInfo.td b/lib/Target/Mips/MipsInstrInfo.td index e0d818b749df..33a061e12a3f 100644 --- a/lib/Target/Mips/MipsInstrInfo.td +++ b/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. @@ -1540,8 +1543,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> : @@ -2068,7 +2072,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>; } @@ -2088,24 +2092,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, @@ -2278,8 +2286,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; @@ -2288,8 +2296,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; @@ -2298,8 +2307,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>; @@ -2433,7 +2453,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/lib/Target/Mips/MipsLongBranch.cpp b/lib/Target/Mips/MipsLongBranch.cpp index bbf2050ce1eb..e6ecbe9b5f66 100644 --- a/lib/Target/Mips/MipsLongBranch.cpp +++ b/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/lib/Target/Mips/MipsSubtarget.cpp b/lib/Target/Mips/MipsSubtarget.cpp index f6af7e22e351..ddaa07ea9bc1 100644 --- a/lib/Target/Mips/MipsSubtarget.cpp +++ b/lib/Target/Mips/MipsSubtarget.cpp @@ -72,9 +72,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)) { @@ -107,6 +108,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/lib/Target/Mips/MipsSubtarget.h b/lib/Target/Mips/MipsSubtarget.h index 8b10b0596e0e..ad2905c51601 100644 --- a/lib/Target/Mips/MipsSubtarget.h +++ b/lib/Target/Mips/MipsSubtarget.h @@ -152,6 +152,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; @@ -272,6 +276,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/test/CodeGen/Mips/indirect-jump-hazard/calls.ll b/test/CodeGen/Mips/indirect-jump-hazard/calls.ll new file mode 100644 index 000000000000..20e89136d87c --- /dev/null +++ b/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/test/CodeGen/Mips/indirect-jump-hazard/guards-verify-call.mir b/test/CodeGen/Mips/indirect-jump-hazard/guards-verify-call.mir new file mode 100644 index 000000000000..1c11d700b53e --- /dev/null +++ b/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/test/CodeGen/Mips/indirect-jump-hazard/guards-verify-tailcall.mir b/test/CodeGen/Mips/indirect-jump-hazard/guards-verify-tailcall.mir new file mode 100644 index 000000000000..00e22b934bbc --- /dev/null +++ b/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/test/CodeGen/Mips/indirect-jump-hazard/jumptables.ll b/test/CodeGen/Mips/indirect-jump-hazard/jumptables.ll new file mode 100644 index 000000000000..c530dd614ef8 --- /dev/null +++ b/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/test/CodeGen/Mips/indirect-jump-hazard/long-branch.ll b/test/CodeGen/Mips/indirect-jump-hazard/long-branch.ll new file mode 100644 index 000000000000..fffda991ae4b --- /dev/null +++ b/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/test/CodeGen/Mips/indirect-jump-hazard/long-calls.ll b/test/CodeGen/Mips/indirect-jump-hazard/long-calls.ll new file mode 100644 index 000000000000..88886e13f326 --- /dev/null +++ b/test/CodeGen/Mips/indirect-jump-hazard/long-calls.ll @@ -0,0 +1,113 @@ +; 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, 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: lui $1, %hi(val) +; O32-NEXT: addiu $1, $1, %lo(val) +; O32-NEXT: lui $2, 20560 +; O32-NEXT: ori $2, $2, 20560 +; O32-NEXT: sw $2, 96($1) +; O32-NEXT: sw $2, 92($1) +; O32-NEXT: sw $2, 88($1) +; O32-NEXT: sw $2, 84($1) +; O32-NEXT: sw $2, 80($1) +; 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: lui $1, %hi(val) +; N32-NEXT: addiu $1, $1, %lo(val) +; N32-NEXT: lui $2, 1285 +; N32-NEXT: daddiu $2, $2, 1285 +; N32-NEXT: dsll $2, $2, 16 +; N32-NEXT: daddiu $2, $2, 1285 +; N32-NEXT: dsll $2, $2, 20 +; N32-NEXT: daddiu $2, $2, 20560 +; N32-NEXT: sdl $2, 88($1) +; N32-NEXT: sdl $2, 80($1) +; N32-NEXT: lui $3, 20560 +; N32-NEXT: ori $3, $3, 20560 +; N32-NEXT: sw $3, 96($1) +; N32-NEXT: sdr $2, 95($1) +; N32-NEXT: sdr $2, 87($1) +; 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: 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 $1, $1, %lo(val) +; N64-NEXT: lui $2, 1285 +; N64-NEXT: daddiu $2, $2, 1285 +; N64-NEXT: dsll $2, $2, 16 +; N64-NEXT: daddiu $2, $2, 1285 +; N64-NEXT: dsll $2, $2, 20 +; N64-NEXT: daddiu $2, $2, 20560 +; N64-NEXT: lui $3, 20560 +; N64-NEXT: sdl $2, 88($1) +; N64-NEXT: sdl $2, 80($1) +; N64-NEXT: ori $3, $3, 20560 +; N64-NEXT: sw $3, 96($1) +; N64-NEXT: sdr $2, 95($1) +; N64-NEXT: sdr $2, 87($1) +; 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* bitcast (i32* getelementptr inbounds ([20 x i32], [20 x i32]* @val, i64 1, i32 0) to i8*), i8 80, i32 20, i32 4, i1 false) + ret void +} + diff --git a/test/CodeGen/Mips/indirect-jump-hazard/unsupported-micromips.ll b/test/CodeGen/Mips/indirect-jump-hazard/unsupported-micromips.ll new file mode 100644 index 000000000000..99612525ae3c --- /dev/null +++ b/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/test/CodeGen/Mips/indirect-jump-hazard/unsupported-mips32.ll b/test/CodeGen/Mips/indirect-jump-hazard/unsupported-mips32.ll new file mode 100644 index 000000000000..48baedf53eaa --- /dev/null +++ b/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 |