diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bf2c21a306f..f8da6cf92119 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ if(NOT DEFINED LLVM_VERSION_MINOR) set(LLVM_VERSION_MINOR 0) endif() if(NOT DEFINED LLVM_VERSION_PATCH) - set(LLVM_VERSION_PATCH 0) + set(LLVM_VERSION_PATCH 1) endif() if(NOT DEFINED LLVM_VERSION_SUFFIX) set(LLVM_VERSION_SUFFIX "") diff --git a/include/llvm/CodeGen/TargetInstrInfo.h b/include/llvm/CodeGen/TargetInstrInfo.h index 6b5404be35d3..57dee3bb44b3 100644 --- a/include/llvm/CodeGen/TargetInstrInfo.h +++ b/include/llvm/CodeGen/TargetInstrInfo.h @@ -421,7 +421,8 @@ class TargetInstrInfo : public MCInstrInfo { /// Build the equivalent inputs of a REG_SEQUENCE for the given \p MI /// and \p DefIdx. /// \p [out] InputRegs of the equivalent REG_SEQUENCE. Each element of - /// the list is modeled as . + /// the list is modeled as . Operands with the undef + /// flag are not added to this list. /// E.g., REG_SEQUENCE %1:sub1, sub0, %2, sub1 would produce /// two elements: /// - %1:sub1, sub0 @@ -446,7 +447,8 @@ class TargetInstrInfo : public MCInstrInfo { /// - %1:sub1, sub0 /// /// \returns true if it is possible to build such an input sequence - /// with the pair \p MI, \p DefIdx. False otherwise. + /// with the pair \p MI, \p DefIdx and the operand has no undef flag set. + /// False otherwise. /// /// \pre MI.isExtractSubreg() or MI.isExtractSubregLike(). /// @@ -465,7 +467,8 @@ class TargetInstrInfo : public MCInstrInfo { /// - InsertedReg: %1:sub1, sub3 /// /// \returns true if it is possible to build such an input sequence - /// with the pair \p MI, \p DefIdx. False otherwise. + /// with the pair \p MI, \p DefIdx and the operand has no undef flag set. + /// False otherwise. /// /// \pre MI.isInsertSubreg() or MI.isInsertSubregLike(). /// diff --git a/lib/Analysis/GlobalsModRef.cpp b/lib/Analysis/GlobalsModRef.cpp index daee93267f56..94306d0f54ad 100644 --- a/lib/Analysis/GlobalsModRef.cpp +++ b/lib/Analysis/GlobalsModRef.cpp @@ -502,6 +502,8 @@ void GlobalsAAResult::AnalyzeCallGraph(CallGraph &CG, Module &M) { } FunctionInfo &FI = FunctionInfos[F]; + Handles.emplace_front(*this, F); + Handles.front().I = Handles.begin(); bool KnowNothing = false; // Collect the mod/ref properties due to called functions. We only compute diff --git a/lib/Analysis/MemorySSA.cpp b/lib/Analysis/MemorySSA.cpp index 6e9368c49d65..09605f61fa93 100644 --- a/lib/Analysis/MemorySSA.cpp +++ b/lib/Analysis/MemorySSA.cpp @@ -153,9 +153,14 @@ class MemoryLocOrCall { if (IsCall != Other.IsCall) return false; - if (IsCall) - return CS.getCalledValue() == Other.CS.getCalledValue(); - return Loc == Other.Loc; + if (!IsCall) + return Loc == Other.Loc; + + if (CS.getCalledValue() != Other.CS.getCalledValue()) + return false; + + return CS.arg_size() == Other.CS.arg_size() && + std::equal(CS.arg_begin(), CS.arg_end(), Other.CS.arg_begin()); } private: @@ -179,12 +184,18 @@ template <> struct DenseMapInfo { } static unsigned getHashValue(const MemoryLocOrCall &MLOC) { - if (MLOC.IsCall) - return hash_combine(MLOC.IsCall, - DenseMapInfo::getHashValue( - MLOC.getCS().getCalledValue())); - return hash_combine( - MLOC.IsCall, DenseMapInfo::getHashValue(MLOC.getLoc())); + if (!MLOC.IsCall) + return hash_combine( + MLOC.IsCall, + DenseMapInfo::getHashValue(MLOC.getLoc())); + + hash_code hash = + hash_combine(MLOC.IsCall, DenseMapInfo::getHashValue( + MLOC.getCS().getCalledValue())); + + for (const Value *Arg : MLOC.getCS().args()) + hash = hash_combine(hash, DenseMapInfo::getHashValue(Arg)); + return hash; } static bool isEqual(const MemoryLocOrCall &LHS, const MemoryLocOrCall &RHS) { diff --git a/lib/CodeGen/LiveDebugVariables.cpp b/lib/CodeGen/LiveDebugVariables.cpp index 42d93a007d77..4ffcffcea693 100644 --- a/lib/CodeGen/LiveDebugVariables.cpp +++ b/lib/CodeGen/LiveDebugVariables.cpp @@ -557,8 +557,11 @@ bool LDVImpl::handleDebugValue(MachineInstr &MI, SlotIndex Idx) { getUserValue(Var, Expr, MI.getDebugLoc()); if (!Discard) UV->addDef(Idx, MI.getOperand(0), IsIndirect); - else - UV->addDef(Idx, MachineOperand::CreateReg(0U, RegState::Debug), false); + else { + MachineOperand MO = MachineOperand::CreateReg(0U, false); + MO.setIsDebug(); + UV->addDef(Idx, MO, false); + } return true; } diff --git a/lib/CodeGen/PeepholeOptimizer.cpp b/lib/CodeGen/PeepholeOptimizer.cpp index 11acbe687a31..1090550243f8 100644 --- a/lib/CodeGen/PeepholeOptimizer.cpp +++ b/lib/CodeGen/PeepholeOptimizer.cpp @@ -1882,6 +1882,8 @@ ValueTrackerResult ValueTracker::getNextSourceFromCopy() { return ValueTrackerResult(); // Otherwise, we want the whole source. const MachineOperand &Src = Def->getOperand(1); + if (Src.isUndef()) + return ValueTrackerResult(); return ValueTrackerResult(Src.getReg(), Src.getSubReg()); } @@ -1925,6 +1927,8 @@ ValueTrackerResult ValueTracker::getNextSourceFromBitcast() { } const MachineOperand &Src = Def->getOperand(SrcIdx); + if (Src.isUndef()) + return ValueTrackerResult(); return ValueTrackerResult(Src.getReg(), Src.getSubReg()); } @@ -2093,6 +2097,10 @@ ValueTrackerResult ValueTracker::getNextSourceFromPHI() { for (unsigned i = 1, e = Def->getNumOperands(); i < e; i += 2) { auto &MO = Def->getOperand(i); assert(MO.isReg() && "Invalid PHI instruction"); + // We have no code to deal with undef operands. They shouldn't happen in + // normal programs anyway. + if (MO.isUndef()) + return ValueTrackerResult(); Res.addSource(MO.getReg(), MO.getSubReg()); } @@ -2149,9 +2157,14 @@ ValueTrackerResult ValueTracker::getNextSource() { // If we can still move up in the use-def chain, move to the next // definition. if (!TargetRegisterInfo::isPhysicalRegister(Reg) && OneRegSrc) { - Def = MRI.getVRegDef(Reg); - DefIdx = MRI.def_begin(Reg).getOperandNo(); - DefSubReg = Res.getSrcSubReg(0); + MachineRegisterInfo::def_iterator DI = MRI.def_begin(Reg); + if (DI != MRI.def_end()) { + Def = DI->getParent(); + DefIdx = DI.getOperandNo(); + DefSubReg = Res.getSrcSubReg(0); + } else { + Def = nullptr; + } return Res; } } diff --git a/lib/CodeGen/TargetInstrInfo.cpp b/lib/CodeGen/TargetInstrInfo.cpp index db925f803db6..bd90ed5b55b8 100644 --- a/lib/CodeGen/TargetInstrInfo.cpp +++ b/lib/CodeGen/TargetInstrInfo.cpp @@ -1151,6 +1151,8 @@ bool TargetInstrInfo::getRegSequenceInputs( for (unsigned OpIdx = 1, EndOpIdx = MI.getNumOperands(); OpIdx != EndOpIdx; OpIdx += 2) { const MachineOperand &MOReg = MI.getOperand(OpIdx); + if (MOReg.isUndef()) + continue; const MachineOperand &MOSubIdx = MI.getOperand(OpIdx + 1); assert(MOSubIdx.isImm() && "One of the subindex of the reg_sequence is not an immediate"); @@ -1174,6 +1176,8 @@ bool TargetInstrInfo::getExtractSubregInputs( // Def = EXTRACT_SUBREG v0.sub1, sub0. assert(DefIdx == 0 && "EXTRACT_SUBREG only has one def"); const MachineOperand &MOReg = MI.getOperand(1); + if (MOReg.isUndef()) + return false; const MachineOperand &MOSubIdx = MI.getOperand(2); assert(MOSubIdx.isImm() && "The subindex of the extract_subreg is not an immediate"); @@ -1198,6 +1202,8 @@ bool TargetInstrInfo::getInsertSubregInputs( assert(DefIdx == 0 && "INSERT_SUBREG only has one def"); const MachineOperand &MOBaseReg = MI.getOperand(1); const MachineOperand &MOInsertedReg = MI.getOperand(2); + if (MOInsertedReg.isUndef()) + return false; const MachineOperand &MOSubIdx = MI.getOperand(3); assert(MOSubIdx.isImm() && "One of the subindex of the reg_sequence is not an immediate"); diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp index 3dc67ad782af..6e65b5e6c807 100644 --- a/lib/Support/Host.cpp +++ b/lib/Support/Host.cpp @@ -1009,7 +1009,7 @@ StringRef sys::getHostCPUName() { #include "llvm/Support/X86TargetParser.def" // Now check types. -#define X86_CPU_SUBTYPE(ARCHNAME, ENUM) \ +#define X86_CPU_TYPE(ARCHNAME, ENUM) \ if (Type == X86::ENUM) \ return ARCHNAME; #include "llvm/Support/X86TargetParser.def" diff --git a/lib/Target/AArch64/AArch64FalkorHWPFFix.cpp b/lib/Target/AArch64/AArch64FalkorHWPFFix.cpp index d1ddb2e3ef70..0d00dab598d5 100644 --- a/lib/Target/AArch64/AArch64FalkorHWPFFix.cpp +++ b/lib/Target/AArch64/AArch64FalkorHWPFFix.cpp @@ -46,6 +46,7 @@ #include "llvm/Pass.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/DebugCounter.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -60,6 +61,8 @@ STATISTIC(NumCollisionsAvoided, "Number of HW prefetch tag collisions avoided"); STATISTIC(NumCollisionsNotAvoided, "Number of HW prefetch tag collisions not avoided due to lack of regsiters"); +DEBUG_COUNTER(FixCounter, "falkor-hwpf", + "Controls which tag collisions are avoided"); namespace { @@ -729,6 +732,21 @@ void FalkorHWPFFix::runOnLoop(MachineLoop &L, MachineFunction &Fn) { bool Fixed = false; DEBUG(dbgs() << "Attempting to fix tag collision: " << MI); + if (!DebugCounter::shouldExecute(FixCounter)) { + DEBUG(dbgs() << "Skipping fix due to debug counter:\n " << MI); + continue; + } + + // Add the non-base registers of MI as live so we don't use them as + // scratch registers. + for (unsigned OpI = 0, OpE = MI.getNumOperands(); OpI < OpE; ++OpI) { + if (OpI == static_cast(LdI.BaseRegIdx)) + continue; + MachineOperand &MO = MI.getOperand(OpI); + if (MO.isReg() && MO.readsReg()) + LR.addReg(MO.getReg()); + } + for (unsigned ScratchReg : AArch64::GPR64RegClass) { if (!LR.available(ScratchReg) || MRI.isReserved(ScratchReg)) continue; diff --git a/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp b/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp index 2042dbf6d5e2..e09263b6fac9 100644 --- a/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp +++ b/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp @@ -147,6 +147,7 @@ extern "C" void LLVMInitializeAMDGPUTarget() { initializeR600PacketizerPass(*PR); initializeR600ExpandSpecialInstrsPassPass(*PR); initializeR600VectorRegMergerPass(*PR); + initializeGlobalISel(*PR); initializeAMDGPUDAGToDAGISelPass(*PR); initializeSILowerI1CopiesPass(*PR); initializeSIFixSGPRCopiesPass(*PR); diff --git a/lib/Target/AMDGPU/SIISelLowering.cpp b/lib/Target/AMDGPU/SIISelLowering.cpp index 6d89aa6968e9..41ca7fe8bfaa 100644 --- a/lib/Target/AMDGPU/SIISelLowering.cpp +++ b/lib/Target/AMDGPU/SIISelLowering.cpp @@ -358,6 +358,7 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM, setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i16, Promote); setOperationAction(ISD::CTLZ, MVT::i16, Promote); setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i16, Promote); + setOperationAction(ISD::CTPOP, MVT::i16, Promote); setOperationAction(ISD::SELECT_CC, MVT::i16, Expand); diff --git a/lib/Target/AMDGPU/SIInstructions.td b/lib/Target/AMDGPU/SIInstructions.td index 9740a18b7248..8c02e8da8d79 100644 --- a/lib/Target/AMDGPU/SIInstructions.td +++ b/lib/Target/AMDGPU/SIInstructions.td @@ -726,6 +726,10 @@ def : GCNPat < (i32 (add (i32 (ctpop i32:$popcnt)), i32:$val)), (V_BCNT_U32_B32_e64 $popcnt, $val) >; +def : GCNPat < + (i16 (add (i16 (trunc (ctpop i32:$popcnt))), i16:$val)), + (V_BCNT_U32_B32_e64 $popcnt, $val) +>; /********** ============================================ **********/ /********** Extraction, Insertion, Building and Casting **********/ diff --git a/lib/Target/ARM/ARMBaseInstrInfo.cpp b/lib/Target/ARM/ARMBaseInstrInfo.cpp index 8c1727724a9e..cff24a10bb5f 100644 --- a/lib/Target/ARM/ARMBaseInstrInfo.cpp +++ b/lib/Target/ARM/ARMBaseInstrInfo.cpp @@ -4864,12 +4864,14 @@ bool ARMBaseInstrInfo::getRegSequenceLikeInputs( // Populate the InputRegs accordingly. // rY const MachineOperand *MOReg = &MI.getOperand(1); - InputRegs.push_back( - RegSubRegPairAndIdx(MOReg->getReg(), MOReg->getSubReg(), ARM::ssub_0)); + if (!MOReg->isUndef()) + InputRegs.push_back(RegSubRegPairAndIdx(MOReg->getReg(), + MOReg->getSubReg(), ARM::ssub_0)); // rZ MOReg = &MI.getOperand(2); - InputRegs.push_back( - RegSubRegPairAndIdx(MOReg->getReg(), MOReg->getSubReg(), ARM::ssub_1)); + if (!MOReg->isUndef()) + InputRegs.push_back(RegSubRegPairAndIdx(MOReg->getReg(), + MOReg->getSubReg(), ARM::ssub_1)); return true; } llvm_unreachable("Target dependent opcode missing"); @@ -4888,6 +4890,8 @@ bool ARMBaseInstrInfo::getExtractSubregLikeInputs( // rX = EXTRACT_SUBREG dZ, ssub_0 // rY = EXTRACT_SUBREG dZ, ssub_1 const MachineOperand &MOReg = MI.getOperand(2); + if (MOReg.isUndef()) + return false; InputReg.Reg = MOReg.getReg(); InputReg.SubReg = MOReg.getSubReg(); InputReg.SubIdx = DefIdx == 0 ? ARM::ssub_0 : ARM::ssub_1; @@ -4907,6 +4911,8 @@ bool ARMBaseInstrInfo::getInsertSubregLikeInputs( // dX = VSETLNi32 dY, rZ, imm const MachineOperand &MOBaseReg = MI.getOperand(1); const MachineOperand &MOInsertedReg = MI.getOperand(2); + if (MOInsertedReg.isUndef()) + return false; const MachineOperand &MOIndex = MI.getOperand(3); BaseReg.Reg = MOBaseReg.getReg(); BaseReg.SubReg = MOBaseReg.getSubReg(); diff --git a/lib/Target/ARM/ARMComputeBlockSize.cpp b/lib/Target/ARM/ARMComputeBlockSize.cpp index 2e97b99b05a7..b263e9d86c42 100644 --- a/lib/Target/ARM/ARMComputeBlockSize.cpp +++ b/lib/Target/ARM/ARMComputeBlockSize.cpp @@ -35,6 +35,7 @@ mayOptimizeThumb2Instruction(const MachineInstr *MI) { case ARM::tBcc: // optimizeThumb2JumpTables. case ARM::t2BR_JT: + case ARM::tBR_JTr: return true; } return false; 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, ISA_MICROMIPS32R6; +def TAILCALLREG_MMR6 : TailCallReg, ISA_MICROMIPS32R6; + +def PseudoIndirectBranch_MMR6 : PseudoIndirectBranchBase, + 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, ISA_MIPS1_NOT_32R6_64R6; +def TAILCALLREG_MM : TailCallReg, + ISA_MICROMIPS32_NOT_MIPS32R6; + +def PseudoIndirectBranch_MM : PseudoIndirectBranchBase, + ISA_MICROMIPS32_NOT_MIPS32R6; + let DecoderNamespace = "MicroMips" in { def RDHWR_MM : MMRel, R6MMR6Rel, ReadHardware, 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 : + PseudoSE<(outs), (ins RO:$rs), [(MipsTailCall RO:$rs)], II_JR>, + PseudoInstExpansion<(JumpInst RT:$rt, RO:$rs)>; +} + +class PseudoIndirectBranchBaseR6 : + 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, ISA_MIPS32R6; + def PseudoIndirectBranchR6 : PseudoIndirectBranchBaseR6, + ISA_MIPS32R6; +} + +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, + UseIndirectJumpsHazard] in { + def TAILCALLHBR6REG : TailCallReg, ISA_MIPS32R6; + def PseudoIndrectHazardBranchR6 : PseudoIndirectBranchBase, + 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; + let AdditionalPredicates = [NoIndirectJumpGuards] in + def JALR64Pseudo : JumpLinkRegPseudo; } +let AdditionalPredicates = [NotInMicroMips], + DecoderNamespace = "Mips64" in { + def JR_HB64 : JR_HB_DESC, JR_HB_ENC, ISA_MIPS32_NOT_32R6_64R6; + def JALR_HB64 : JALR_HB_DESC, JALR_HB_ENC, ISA_MIPS32R2; +} +def PseudoReturn64 : PseudoReturnBase; -def TAILCALLREG64 : TailCallReg; +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, + NoIndirectJumpGuards] in { + def TAILCALLREG64 : TailCallReg, ISA_MIPS3_NOT_32R6_64R6, + PTR_64; + def PseudoIndirectBranch64 : PseudoIndirectBranchBase, + ISA_MIPS3_NOT_32R6_64R6; +} -def PseudoReturn64 : PseudoReturnBase; -def PseudoIndirectBranch64 : PseudoIndirectBranchBase; +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, + UseIndirectJumpsHazard] in { + def TAILCALLREGHB64 : TailCallReg, + ISA_MIPS32R2_NOT_32R6_64R6, PTR_64; + def PseudoIndirectHazardBranch64 : PseudoIndirectBranchBase, + 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; + //===----------------------------------------------------------------------===// // 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, ISA_MIPS64R6; + def PseudoIndirectBranch64R6 : PseudoIndirectBranchBaseR6, + ISA_MIPS64R6; +} + +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, + UseIndirectJumpsHazard] in { + def TAILCALLHB64R6REG : TailCallReg, + ISA_MIPS64R6; + def PseudoIndrectHazardBranch64R6 : PseudoIndirectBranchBase, + 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 class PseudoDSP pattern, InstrItinClass itin = IIPseudo> - : MipsPseudo, PredicateControl { + : MipsPseudo { let InsnPredicates = [HasDSP]; } diff --git a/lib/Target/Mips/MipsFastISel.cpp b/lib/Target/Mips/MipsFastISel.cpp index 8bbac3ed7cfb..d3048c7390e1 100644 --- a/lib/Target/Mips/MipsFastISel.cpp +++ b/lib/Target/Mips/MipsFastISel.cpp @@ -67,6 +67,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include +#include #include #include @@ -1306,13 +1307,13 @@ bool MipsFastISel::fastLowerArguments() { return false; } - const ArrayRef GPR32ArgRegs = {Mips::A0, Mips::A1, Mips::A2, - Mips::A3}; - const ArrayRef FGR32ArgRegs = {Mips::F12, Mips::F14}; - const ArrayRef AFGR64ArgRegs = {Mips::D6, Mips::D7}; - ArrayRef::iterator NextGPR32 = GPR32ArgRegs.begin(); - ArrayRef::iterator NextFGR32 = FGR32ArgRegs.begin(); - ArrayRef::iterator NextAFGR64 = AFGR64ArgRegs.begin(); + std::array GPR32ArgRegs = {{Mips::A0, Mips::A1, Mips::A2, + Mips::A3}}; + std::array FGR32ArgRegs = {{Mips::F12, Mips::F14}}; + std::array AFGR64ArgRegs = {{Mips::D6, Mips::D7}}; + auto NextGPR32 = GPR32ArgRegs.begin(); + auto NextFGR32 = FGR32ArgRegs.begin(); + auto NextAFGR64 = AFGR64ArgRegs.begin(); struct AllocatedReg { const TargetRegisterClass *RC; 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 pattern, // Mips Pseudo Instructions Format class MipsPseudo pattern, InstrItinClass itin = IIPseudo> : - MipsInst { + MipsInst, PredicateControl { let isCodeGenOnly = 1; let isPseudo = 1; } @@ -136,7 +136,7 @@ class MipsPseudo pattern, // Mips32/64 Pseudo Instruction Format class PseudoSE pattern, InstrItinClass itin = IIPseudo> : - MipsPseudo, PredicateControl { + MipsPseudo { 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 : - PseudoSE<(outs), (ins RO:$rs), [(MipsTailCall RO:$rs)], II_JR>; + class TailCallReg : + PseudoSE<(outs), (ins RO:$rs), [(MipsTailCall RO:$rs)], II_JR>, + PseudoInstExpansion<(JumpInst RO:$rs)>; } class BAL_BR_Pseudo : @@ -2068,7 +2072,7 @@ def B : UncondBranch, 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; } @@ -2088,24 +2092,28 @@ def BAL_BR : BAL_BR_Pseudo; let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips] in { def TAILCALL : TailCall; } - -def TAILCALLREG : TailCallReg; +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, + NoIndirectJumpGuards] in + def TAILCALLREG : TailCallReg, 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 : +class PseudoIndirectBranchBase : 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; +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, + NoIndirectJumpGuards] in + def PseudoIndirectBranch : PseudoIndirectBranchBase, + 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 { list Pattern = []; } -class JR_HB_DESC : InstSE<(outs), (ins), "", [], II_JR_HB, FrmJ>, - JR_HB_DESC_BASE<"jr.hb", GPR32Opnd> { +class JR_HB_DESC : + 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 : + 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, JR_HB_ENC, ISA_MIPS32R2_NOT_32R6_64R6; +def JALR_HB : JALR_HB_DESC, JALR_HB_ENC, ISA_MIPS32; + +let AdditionalPredicates = [NotInMicroMips, UseIndirectJumpsHazard] in + def JALRHBPseudo : JumpLinkRegPseudo; + + +let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips, + UseIndirectJumpsHazard] in { + def TAILCALLREGHB : TailCallReg, ISA_MIPS32_NOT_32R6_64R6; + def PseudoIndirectHazardBranch : PseudoIndirectBranchBase, + ISA_MIPS32R2_NOT_32R6_64R6; +} class TLB : 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 @@ class MipsSubtarget : public MipsGenSubtargetInfo { 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/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp index f0e8b11a3d9c..26e9f13f9ff4 100644 --- a/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/lib/Target/PowerPC/PPCISelLowering.cpp @@ -12264,6 +12264,11 @@ SDValue PPCTargetLowering::PerformDAGCombine(SDNode *N, N->getOperand(1).getValueType() == MVT::i16 || (Subtarget.hasLDBRX() && Subtarget.isPPC64() && N->getOperand(1).getValueType() == MVT::i64))) { + // STBRX can only handle simple types. + EVT mVT = cast(N)->getMemoryVT(); + if (mVT.isExtended()) + break; + SDValue BSwapOp = N->getOperand(1).getOperand(0); // Do an any-extend to 32-bits if this is a half-word input. if (BSwapOp.getValueType() == MVT::i16) @@ -12271,7 +12276,6 @@ SDValue PPCTargetLowering::PerformDAGCombine(SDNode *N, // If the type of BSWAP operand is wider than stored memory width // it need to be shifted to the right side before STBRX. - EVT mVT = cast(N)->getMemoryVT(); if (Op1VT.bitsGT(mVT)) { int Shift = Op1VT.getSizeInBits() - mVT.getSizeInBits(); BSwapOp = DAG.getNode(ISD::SRL, dl, Op1VT, BSwapOp, diff --git a/lib/Target/PowerPC/PPCInstrInfo.cpp b/lib/Target/PowerPC/PPCInstrInfo.cpp index fb16700a5e17..4ef71effd49b 100644 --- a/lib/Target/PowerPC/PPCInstrInfo.cpp +++ b/lib/Target/PowerPC/PPCInstrInfo.cpp @@ -2431,7 +2431,8 @@ bool PPCInstrInfo::convertToImmediateForm(MachineInstr &MI, // Use APInt's rotate function. int64_t SH = MI.getOperand(2).getImm(); int64_t MB = MI.getOperand(3).getImm(); - APInt InVal(Opc == PPC::RLDICL ? 64 : 32, SExtImm, true); + APInt InVal((Opc == PPC::RLDICL || Opc == PPC::RLDICLo) ? + 64 : 32, SExtImm, true); InVal = InVal.rotl(SH); uint64_t Mask = (1LLU << (63 - MB + 1)) - 1; InVal &= Mask; @@ -2444,6 +2445,8 @@ bool PPCInstrInfo::convertToImmediateForm(MachineInstr &MI, Is64BitLI = Opc != PPC::RLDICL_32; NewImm = InVal.getSExtValue(); SetCR = Opc == PPC::RLDICLo; + if (SetCR && (SExtImm & NewImm) != NewImm) + return false; break; } return false; @@ -2471,6 +2474,8 @@ bool PPCInstrInfo::convertToImmediateForm(MachineInstr &MI, Is64BitLI = Opc == PPC::RLWINM8 || Opc == PPC::RLWINM8o; NewImm = InVal.getSExtValue(); SetCR = Opc == PPC::RLWINMo || Opc == PPC::RLWINM8o; + if (SetCR && (SExtImm & NewImm) != NewImm) + return false; break; } return false; diff --git a/lib/Transforms/IPO/ArgumentPromotion.cpp b/lib/Transforms/IPO/ArgumentPromotion.cpp index b25cbcad3b9d..76c4a8fbc16e 100644 --- a/lib/Transforms/IPO/ArgumentPromotion.cpp +++ b/lib/Transforms/IPO/ArgumentPromotion.cpp @@ -847,10 +847,20 @@ promoteArguments(Function *F, function_ref AARGetter, if (CS.getInstruction() == nullptr || !CS.isCallee(&U)) return nullptr; + // Can't change signature of musttail callee + if (CS.isMustTailCall()) + return nullptr; + if (CS.getInstruction()->getParent()->getParent() == F) isSelfRecursive = true; } + // Can't change signature of musttail caller + // FIXME: Support promoting whole chain of musttail functions + for (BasicBlock &BB : *F) + if (BB.getTerminatingMustTailCall()) + return nullptr; + const DataLayout &DL = F->getParent()->getDataLayout(); AAResults &AAR = AARGetter(*F); diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index 4bb2984e3b47..e0bbf45d316a 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -2099,8 +2099,31 @@ static void RemoveNestAttribute(Function *F) { /// GHC, or anyregcc. static bool isProfitableToMakeFastCC(Function *F) { CallingConv::ID CC = F->getCallingConv(); + // FIXME: Is it worth transforming x86_stdcallcc and x86_fastcallcc? - return CC == CallingConv::C || CC == CallingConv::X86_ThisCall; + if (CC != CallingConv::C && CC != CallingConv::X86_ThisCall) + return false; + + // FIXME: Change CC for the whole chain of musttail calls when possible. + // + // Can't change CC of the function that either has musttail calls, or is a + // musttail callee itself + for (User *U : F->users()) { + if (isa(U)) + continue; + CallInst* CI = dyn_cast(U); + if (!CI) + continue; + + if (CI->isMustTailCall()) + return false; + } + + for (BasicBlock &BB : *F) + if (BB.getTerminatingMustTailCall()) + return false; + + return true; } static bool diff --git a/lib/Transforms/InstCombine/InstructionCombining.cpp b/lib/Transforms/InstCombine/InstructionCombining.cpp index b332e75c7feb..35ed592ac07d 100644 --- a/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -34,6 +34,7 @@ //===----------------------------------------------------------------------===// #include "InstCombineInternal.h" +#include "llvm-c/Initialization.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" diff --git a/lib/Transforms/Scalar/CallSiteSplitting.cpp b/lib/Transforms/Scalar/CallSiteSplitting.cpp index 4edea7cc3c82..7488cd5af8be 100644 --- a/lib/Transforms/Scalar/CallSiteSplitting.cpp +++ b/lib/Transforms/Scalar/CallSiteSplitting.cpp @@ -201,6 +201,46 @@ static bool canSplitCallSite(CallSite CS) { return CallSiteBB->canSplitPredecessors(); } +static Instruction *cloneInstForMustTail(Instruction *I, Instruction *Before, + Value *V) { + Instruction *Copy = I->clone(); + Copy->setName(I->getName()); + Copy->insertBefore(Before); + if (V) + Copy->setOperand(0, V); + return Copy; +} + +/// Copy mandatory `musttail` return sequence that follows original `CI`, and +/// link it up to `NewCI` value instead: +/// +/// * (optional) `bitcast NewCI to ...` +/// * `ret bitcast or NewCI` +/// +/// Insert this sequence right before `SplitBB`'s terminator, which will be +/// cleaned up later in `splitCallSite` below. +static void copyMustTailReturn(BasicBlock *SplitBB, Instruction *CI, + Instruction *NewCI) { + bool IsVoid = SplitBB->getParent()->getReturnType()->isVoidTy(); + auto II = std::next(CI->getIterator()); + + BitCastInst *BCI = dyn_cast(&*II); + if (BCI) + ++II; + + ReturnInst *RI = dyn_cast(&*II); + assert(RI && "`musttail` call must be followed by `ret` instruction"); + + TerminatorInst *TI = SplitBB->getTerminator(); + Value *V = NewCI; + if (BCI) + V = cloneInstForMustTail(BCI, TI, V); + cloneInstForMustTail(RI, TI, IsVoid ? nullptr : V); + + // FIXME: remove TI here, `DuplicateInstructionsInSplitBetween` has a bug + // that prevents doing this now. +} + /// Return true if the CS is split into its new predecessors which are directly /// hooked to each of its original predecessors pointed by PredBB1 and PredBB2. /// CallInst1 and CallInst2 will be the new call-sites placed in the new @@ -245,6 +285,7 @@ static void splitCallSite(CallSite CS, BasicBlock *PredBB1, BasicBlock *PredBB2, Instruction *CallInst1, Instruction *CallInst2) { Instruction *Instr = CS.getInstruction(); BasicBlock *TailBB = Instr->getParent(); + bool IsMustTailCall = CS.isMustTailCall(); assert(Instr == (TailBB->getFirstNonPHIOrDbg()) && "Unexpected call-site"); BasicBlock *SplitBlock1 = @@ -276,9 +317,14 @@ static void splitCallSite(CallSite CS, BasicBlock *PredBB1, BasicBlock *PredBB2, ++ArgNo; } } + // Clone and place bitcast and return instructions before `TI` + if (IsMustTailCall) { + copyMustTailReturn(SplitBlock1, CS.getInstruction(), CallInst1); + copyMustTailReturn(SplitBlock2, CS.getInstruction(), CallInst2); + } // Replace users of the original call with a PHI mering call-sites split. - if (Instr->getNumUses()) { + if (!IsMustTailCall && Instr->getNumUses()) { PHINode *PN = PHINode::Create(Instr->getType(), 2, "phi.call", TailBB->getFirstNonPHI()); PN->addIncoming(CallInst1, SplitBlock1); @@ -290,8 +336,25 @@ static void splitCallSite(CallSite CS, BasicBlock *PredBB1, BasicBlock *PredBB2, << "\n"); DEBUG(dbgs() << " " << *CallInst2 << " in " << SplitBlock2->getName() << "\n"); - Instr->eraseFromParent(); + NumCallSiteSplit++; + + // FIXME: remove TI in `copyMustTailReturn` + if (IsMustTailCall) { + // Remove superfluous `br` terminators from the end of the Split blocks + // NOTE: Removing terminator removes the SplitBlock from the TailBB's + // predecessors. Therefore we must get complete list of Splits before + // attempting removal. + SmallVector Splits(predecessors((TailBB))); + assert(Splits.size() == 2 && "Expected exactly 2 splits!"); + for (unsigned i = 0; i < Splits.size(); i++) + Splits[i]->getTerminator()->eraseFromParent(); + + // Erase the tail block once done with musttail patching + TailBB->eraseFromParent(); + return; + } + Instr->eraseFromParent(); } // Return true if the call-site has an argument which is a PHI with only @@ -369,7 +432,17 @@ static bool doCallSiteSplitting(Function &F, TargetLibraryInfo &TLI) { Function *Callee = CS.getCalledFunction(); if (!Callee || Callee->isDeclaration()) continue; + + // Successful musttail call-site splits result in erased CI and erased BB. + // Check if such path is possible before attempting the splitting. + bool IsMustTail = CS.isMustTailCall(); + Changed |= tryToSplitCallSite(CS); + + // There're no interesting instructions after this. The call site + // itself might have been erased on splitting. + if (IsMustTail) + break; } } return Changed; diff --git a/lib/Transforms/Scalar/SCCP.cpp b/lib/Transforms/Scalar/SCCP.cpp index 9dc550ceaeca..69636ed3ac8b 100644 --- a/lib/Transforms/Scalar/SCCP.cpp +++ b/lib/Transforms/Scalar/SCCP.cpp @@ -223,6 +223,10 @@ class SCCPSolver : public InstVisitor { /// represented here for efficient lookup. SmallPtrSet MRVFunctionsTracked; + /// MustTailFunctions - Each function here is a callee of non-removable + /// musttail call site. + SmallPtrSet MustTailCallees; + /// TrackingIncomingArguments - This is the set of functions for whose /// arguments we make optimistic assumptions about and try to prove as /// constants. @@ -289,6 +293,18 @@ class SCCPSolver : public InstVisitor { TrackedRetVals.insert(std::make_pair(F, LatticeVal())); } + /// AddMustTailCallee - If the SCCP solver finds that this function is called + /// from non-removable musttail call site. + void AddMustTailCallee(Function *F) { + MustTailCallees.insert(F); + } + + /// Returns true if the given function is called from non-removable musttail + /// call site. + bool isMustTailCallee(Function *F) { + return MustTailCallees.count(F); + } + void AddArgumentTrackedFunction(Function *F) { TrackingIncomingArguments.insert(F); } @@ -358,6 +374,12 @@ class SCCPSolver : public InstVisitor { return MRVFunctionsTracked; } + /// getMustTailCallees - Get the set of functions which are called + /// from non-removable musttail call sites. + const SmallPtrSet getMustTailCallees() { + return MustTailCallees; + } + /// markOverdefined - Mark the specified value overdefined. This /// works with both scalars and structs. void markOverdefined(Value *V) { @@ -1672,6 +1694,23 @@ static bool tryToReplaceWithConstant(SCCPSolver &Solver, Value *V) { IV.isConstant() ? IV.getConstant() : UndefValue::get(V->getType()); } assert(Const && "Constant is nullptr here!"); + + // Replacing `musttail` instructions with constant breaks `musttail` invariant + // unless the call itself can be removed + CallInst *CI = dyn_cast(V); + if (CI && CI->isMustTailCall() && !isInstructionTriviallyDead(CI)) { + CallSite CS(CI); + Function *F = CS.getCalledFunction(); + + // Don't zap returns of the callee + if (F) + Solver.AddMustTailCallee(F); + + DEBUG(dbgs() << " Can\'t treat the result of musttail call : " << *CI + << " as a constant\n"); + return false; + } + DEBUG(dbgs() << " Constant: " << *Const << " = " << *V << '\n'); // Replaces all of the uses of a variable with uses of the constant. @@ -1802,10 +1841,25 @@ static void findReturnsToZap(Function &F, if (!Solver.isArgumentTrackedFunction(&F)) return; - for (BasicBlock &BB : F) + // There is a non-removable musttail call site of this function. Zapping + // returns is not allowed. + if (Solver.isMustTailCallee(&F)) { + DEBUG(dbgs() << "Can't zap returns of the function : " << F.getName() + << " due to present musttail call of it\n"); + return; + } + + for (BasicBlock &BB : F) { + if (CallInst *CI = BB.getTerminatingMustTailCall()) { + DEBUG(dbgs() << "Can't zap return of the block due to present " + << "musttail call : " << *CI << "\n"); + return; + } + if (auto *RI = dyn_cast(BB.getTerminator())) if (!isa(RI->getOperand(0))) ReturnsToZap.push_back(RI); + } } static bool runIPSCCP(Module &M, const DataLayout &DL, diff --git a/test/Analysis/MemorySSA/pr36883.ll b/test/Analysis/MemorySSA/pr36883.ll new file mode 100644 index 000000000000..8411b0c228b8 --- /dev/null +++ b/test/Analysis/MemorySSA/pr36883.ll @@ -0,0 +1,38 @@ +; RUN: opt -basicaa -memoryssa -analyze < %s 2>&1 -S | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print,verify' -S < %s 2>&1 | FileCheck %s +; +; We weren't properly considering the args in callsites in equality or hashing. + +target triple = "armv7-dcg-linux-gnueabi" + +; CHECK-LABEL: define <8 x i16> @vpx_idct32_32_neon +define <8 x i16> @vpx_idct32_32_neon(i8* %p, <8 x i16> %v) { +entry: +; CHECK: MemoryUse(liveOnEntry) + %load1 = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 2) #4 ; load CSE replacement + +; CHECK: 1 = MemoryDef(liveOnEntry) + call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %p, <8 x i16> %v, i32 2) #4 ; clobber + + %p_next = getelementptr inbounds i8, i8* %p, i32 16 +; CHECK: MemoryUse(liveOnEntry) + %load2 = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p_next, i32 2) #4 ; non-aliasing load needed to trigger bug + +; CHECK: MemoryUse(1) + %load3 = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 2) #4 ; load CSE removed + + %add = add <8 x i16> %load1, %load2 + %ret = add <8 x i16> %add, %load3 + ret <8 x i16> %ret +} + +; Function Attrs: argmemonly nounwind readonly +declare <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8*, i32) #2 + +; Function Attrs: argmemonly nounwind +declare void @llvm.arm.neon.vst1.p0i8.v8i16(i8*, <8 x i16>, i32) #1 + +attributes #1 = { argmemonly nounwind } +attributes #2 = { argmemonly nounwind readonly } +attributes #3 = { nounwind readnone } +attributes #4 = { nounwind } diff --git a/test/CodeGen/AArch64/falkor-hwpf-fix.mir b/test/CodeGen/AArch64/falkor-hwpf-fix.mir index 38622ae0e49a..28b19f877685 100644 --- a/test/CodeGen/AArch64/falkor-hwpf-fix.mir +++ b/test/CodeGen/AArch64/falkor-hwpf-fix.mir @@ -353,3 +353,28 @@ body: | bb.1: RET_ReallyLR ... +--- +# Check that non-base registers are considered live when finding a +# scratch register by making sure we don't use %x2 for the scratch +# register for the inserted ORRXrs. +# CHECK-LABEL: name: hwpf_offreg +# CHECK: %x3 = ORRXrs %xzr, %x1, 0 +# CHECK: %w10 = LDRWroX %x3, %x2, 0, 0 +name: hwpf_offreg +tracksRegLiveness: true +body: | + bb.0: + liveins: %w0, %x1, %x2, %x17, %x18 + + %w10 = LDRWroX %x1, %x2, 0, 0 :: ("aarch64-strided-access" load 4) + + %x2 = ORRXrs %xzr, %x10, 0 + %w26 = LDRWroX %x1, %x2, 0, 0 + + %w0 = SUBWri %w0, 1, 0 + %wzr = SUBSWri %w0, 0, 0, implicit-def %nzcv + Bcc 9, %bb.0, implicit %nzcv + + bb.1: + RET_ReallyLR +... diff --git a/test/CodeGen/AMDGPU/ctpop16.ll b/test/CodeGen/AMDGPU/ctpop16.ll new file mode 100644 index 000000000000..8236ac07a680 --- /dev/null +++ b/test/CodeGen/AMDGPU/ctpop16.ll @@ -0,0 +1,334 @@ +; RUN: llc -march=amdgcn -mcpu=tahiti -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefix=GCN -check-prefix=FUNC -check-prefix=SI %s +; RUN: llc -march=amdgcn -mcpu=tonga -mattr=-flat-for-global -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefix=GCN -check-prefix=FUNC -check-prefix=VI %s +; RUN: llc -march=r600 -mcpu=cypress -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefix=EG -check-prefix=FUNC %s + +declare i16 @llvm.ctpop.i16(i16) nounwind readnone +declare <2 x i16> @llvm.ctpop.v2i16(<2 x i16>) nounwind readnone +declare <4 x i16> @llvm.ctpop.v4i16(<4 x i16>) nounwind readnone +declare <8 x i16> @llvm.ctpop.v8i16(<8 x i16>) nounwind readnone +declare <16 x i16> @llvm.ctpop.v16i16(<16 x i16>) nounwind readnone + +declare i32 @llvm.r600.read.tidig.x() nounwind readnone + +; FUNC-LABEL: {{^}}s_ctpop_i16: +; GCN: s_load_dword [[SVAL:s[0-9]+]], +; GCN: s_bcnt1_i32_b32 [[SRESULT:s[0-9]+]], [[SVAL]] +; GCN: v_mov_b32_e32 [[VRESULT:v[0-9]+]], [[SRESULT]] +; GCN: buffer_store_short [[VRESULT]], +; GCN: s_endpgm + +; EG: BCNT_INT +define amdgpu_kernel void @s_ctpop_i16(i16 addrspace(1)* noalias %out, i16 %val) nounwind { + %ctpop = call i16 @llvm.ctpop.i16(i16 %val) nounwind readnone + store i16 %ctpop, i16 addrspace(1)* %out, align 4 + ret void +} + +; XXX - Why 0 in register? +; FUNC-LABEL: {{^}}v_ctpop_i16: +; GCN: {{buffer|flat}}_load_ushort [[VAL:v[0-9]+]], +; GCN: v_bcnt_u32_b32{{(_e64)*}} [[RESULT:v[0-9]+]], [[VAL]], 0 +; GCN: buffer_store_short [[RESULT]], +; GCN: s_endpgm + +; EG: BCNT_INT +define amdgpu_kernel void @v_ctpop_i16(i16 addrspace(1)* noalias %out, i16 addrspace(1)* noalias %in) nounwind { + %tid = call i32 @llvm.r600.read.tidig.x() + %in.gep = getelementptr i16, i16 addrspace(1)* %in, i32 %tid + %val = load i16, i16 addrspace(1)* %in.gep, align 4 + %ctpop = call i16 @llvm.ctpop.i16(i16 %val) nounwind readnone + store i16 %ctpop, i16 addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: {{^}}v_ctpop_add_chain_i16: +; SI: buffer_load_ushort [[VAL0:v[0-9]+]], +; SI: buffer_load_ushort [[VAL1:v[0-9]+]], +; VI: flat_load_ushort [[VAL0:v[0-9]+]], +; VI: flat_load_ushort [[VAL1:v[0-9]+]], +; GCN: v_bcnt_u32_b32{{(_e64)*}} [[MIDRESULT:v[0-9]+]], [[VAL1]], 0 +; SI: v_bcnt_u32_b32_e32 [[RESULT:v[0-9]+]], [[VAL0]], [[MIDRESULT]] +; VI: v_bcnt_u32_b32 [[RESULT:v[0-9]+]], [[VAL0]], [[MIDRESULT]] +; GCN: buffer_store_short [[RESULT]], +; GCN: s_endpgm + +; EG: BCNT_INT +; EG: BCNT_INT +define amdgpu_kernel void @v_ctpop_add_chain_i16(i16 addrspace(1)* noalias %out, i16 addrspace(1)* noalias %in0, i16 addrspace(1)* noalias %in1) nounwind { + %tid = call i32 @llvm.r600.read.tidig.x() + %in0.gep = getelementptr i16, i16 addrspace(1)* %in0, i32 %tid + %in1.gep = getelementptr i16, i16 addrspace(1)* %in1, i32 %tid + %val0 = load volatile i16, i16 addrspace(1)* %in0.gep, align 4 + %val1 = load volatile i16, i16 addrspace(1)* %in1.gep, align 4 + %ctpop0 = call i16 @llvm.ctpop.i16(i16 %val0) nounwind readnone + %ctpop1 = call i16 @llvm.ctpop.i16(i16 %val1) nounwind readnone + %add = add i16 %ctpop0, %ctpop1 + store i16 %add, i16 addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: {{^}}v_ctpop_add_sgpr_i16: +; GCN: {{buffer|flat}}_load_ushort [[VAL0:v[0-9]+]], +; GCN: s_waitcnt +; GCN-NEXT: v_bcnt_u32_b32{{(_e64)*}} [[RESULT:v[0-9]+]], [[VAL0]], s{{[0-9]+}} +; GCN: buffer_store_short [[RESULT]], +; GCN: s_endpgm +define amdgpu_kernel void @v_ctpop_add_sgpr_i16(i16 addrspace(1)* noalias %out, i16 addrspace(1)* noalias %in, i16 %sval) nounwind { + %tid = call i32 @llvm.r600.read.tidig.x() + %in.gep = getelementptr i16, i16 addrspace(1)* %in, i32 %tid + %val = load i16, i16 addrspace(1)* %in.gep, align 4 + %ctpop = call i16 @llvm.ctpop.i16(i16 %val) nounwind readnone + %add = add i16 %ctpop, %sval + store i16 %add, i16 addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: {{^}}v_ctpop_v2i16: +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: s_endpgm + +; EG: BCNT_INT +; EG: BCNT_INT +define amdgpu_kernel void @v_ctpop_v2i16(<2 x i16> addrspace(1)* noalias %out, <2 x i16> addrspace(1)* noalias %in) nounwind { + %tid = call i32 @llvm.r600.read.tidig.x() + %in.gep = getelementptr <2 x i16>, <2 x i16> addrspace(1)* %in, i32 %tid + %val = load <2 x i16>, <2 x i16> addrspace(1)* %in.gep, align 8 + %ctpop = call <2 x i16> @llvm.ctpop.v2i16(<2 x i16> %val) nounwind readnone + store <2 x i16> %ctpop, <2 x i16> addrspace(1)* %out, align 8 + ret void +} + +; FUNC-LABEL: {{^}}v_ctpop_v4i16: +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: s_endpgm + +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +define amdgpu_kernel void @v_ctpop_v4i16(<4 x i16> addrspace(1)* noalias %out, <4 x i16> addrspace(1)* noalias %in) nounwind { + %tid = call i32 @llvm.r600.read.tidig.x() + %in.gep = getelementptr <4 x i16>, <4 x i16> addrspace(1)* %in, i32 %tid + %val = load <4 x i16>, <4 x i16> addrspace(1)* %in.gep, align 16 + %ctpop = call <4 x i16> @llvm.ctpop.v4i16(<4 x i16> %val) nounwind readnone + store <4 x i16> %ctpop, <4 x i16> addrspace(1)* %out, align 16 + ret void +} + +; FUNC-LABEL: {{^}}v_ctpop_v8i16: +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: s_endpgm + +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +define amdgpu_kernel void @v_ctpop_v8i16(<8 x i16> addrspace(1)* noalias %out, <8 x i16> addrspace(1)* noalias %in) nounwind { + %tid = call i32 @llvm.r600.read.tidig.x() + %in.gep = getelementptr <8 x i16>, <8 x i16> addrspace(1)* %in, i32 %tid + %val = load <8 x i16>, <8 x i16> addrspace(1)* %in.gep, align 32 + %ctpop = call <8 x i16> @llvm.ctpop.v8i16(<8 x i16> %val) nounwind readnone + store <8 x i16> %ctpop, <8 x i16> addrspace(1)* %out, align 32 + ret void +} + +; FUNC-LABEL: {{^}}v_ctpop_v16i16: +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: v_bcnt_u32_b32{{(_e64)*}} +; GCN: s_endpgm + +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +; EG: BCNT_INT +define amdgpu_kernel void @v_ctpop_v16i16(<16 x i16> addrspace(1)* noalias %out, <16 x i16> addrspace(1)* noalias %in) nounwind { + %tid = call i32 @llvm.r600.read.tidig.x() + %in.gep = getelementptr <16 x i16>, <16 x i16> addrspace(1)* %in, i32 %tid + %val = load <16 x i16>, <16 x i16> addrspace(1)* %in.gep, align 32 + %ctpop = call <16 x i16> @llvm.ctpop.v16i16(<16 x i16> %val) nounwind readnone + store <16 x i16> %ctpop, <16 x i16> addrspace(1)* %out, align 32 + ret void +} + +; FUNC-LABEL: {{^}}v_ctpop_i16_add_inline_constant: +; GCN: {{buffer|flat}}_load_ushort [[VAL:v[0-9]+]], +; GCN: v_bcnt_u32_b32{{(_e64)*}} [[RESULT:v[0-9]+]], [[VAL]], 4 +; GCN: buffer_store_short [[RESULT]], +; GCN: s_endpgm + +; EG: BCNT_INT +define amdgpu_kernel void @v_ctpop_i16_add_inline_constant(i16 addrspace(1)* noalias %out, i16 addrspace(1)* noalias %in) nounwind { + %tid = call i32 @llvm.r600.read.tidig.x() + %in.gep = getelementptr i16, i16 addrspace(1)* %in, i32 %tid + %val = load i16, i16 addrspace(1)* %in.gep, align 4 + %ctpop = call i16 @llvm.ctpop.i16(i16 %val) nounwind readnone + %add = add i16 %ctpop, 4 + store i16 %add, i16 addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: {{^}}v_ctpop_i16_add_inline_constant_inv: +; GCN: {{buffer|flat}}_load_ushort [[VAL:v[0-9]+]], +; GCN: v_bcnt_u32_b32{{(_e64)*}} [[RESULT:v[0-9]+]], [[VAL]], 4 +; GCN: buffer_store_short [[RESULT]], +; GCN: s_endpgm + +; EG: BCNT_INT +define amdgpu_kernel void @v_ctpop_i16_add_inline_constant_inv(i16 addrspace(1)* noalias %out, i16 addrspace(1)* noalias %in) nounwind { + %tid = call i32 @llvm.r600.read.tidig.x() + %in.gep = getelementptr i16, i16 addrspace(1)* %in, i32 %tid + %val = load i16, i16 addrspace(1)* %in.gep, align 4 + %ctpop = call i16 @llvm.ctpop.i16(i16 %val) nounwind readnone + %add = add i16 4, %ctpop + store i16 %add, i16 addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: {{^}}v_ctpop_i16_add_literal: +; GCN-DAG: {{buffer|flat}}_load_ushort [[VAL:v[0-9]+]], +; SI-DAG: v_mov_b32_e32 [[LIT:v[0-9]+]], 0x3e7 +; VI-DAG: s_movk_i32 [[LIT:s[0-9]+]], 0x3e7 +; SI: v_bcnt_u32_b32_e32 [[RESULT:v[0-9]+]], [[VAL]], [[LIT]] +; VI: v_bcnt_u32_b32 [[RESULT:v[0-9]+]], [[VAL]], [[LIT]] +; GCN: buffer_store_short [[RESULT]], +; GCN: s_endpgm +define amdgpu_kernel void @v_ctpop_i16_add_literal(i16 addrspace(1)* noalias %out, i16 addrspace(1)* noalias %in) nounwind { + %tid = call i32 @llvm.r600.read.tidig.x() + %in.gep = getelementptr i16, i16 addrspace(1)* %in, i32 %tid + %val = load i16, i16 addrspace(1)* %in.gep, align 4 + %ctpop = call i16 @llvm.ctpop.i16(i16 %val) nounwind readnone + %add = add i16 %ctpop, 999 + store i16 %add, i16 addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: {{^}}v_ctpop_i16_add_var: +; GCN-DAG: {{buffer|flat}}_load_ushort [[VAL:v[0-9]+]], +; GCN-DAG: s_load_dword [[VAR:s[0-9]+]], +; GCN: v_bcnt_u32_b32{{(_e64)*}} [[RESULT:v[0-9]+]], [[VAL]], [[VAR]] +; GCN: buffer_store_short [[RESULT]], +; GCN: s_endpgm + +; EG: BCNT_INT +define amdgpu_kernel void @v_ctpop_i16_add_var(i16 addrspace(1)* noalias %out, i16 addrspace(1)* noalias %in, i16 %const) nounwind { + %tid = call i32 @llvm.r600.read.tidig.x() + %in.gep = getelementptr i16, i16 addrspace(1)* %in, i32 %tid + %val = load i16, i16 addrspace(1)* %in.gep, align 4 + %ctpop = call i16 @llvm.ctpop.i16(i16 %val) nounwind readnone + %add = add i16 %ctpop, %const + store i16 %add, i16 addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: {{^}}v_ctpop_i16_add_var_inv: +; GCN-DAG: {{buffer|flat}}_load_ushort [[VAL:v[0-9]+]], +; GCN-DAG: s_load_dword [[VAR:s[0-9]+]], +; GCN: v_bcnt_u32_b32{{(_e64)*}} [[RESULT:v[0-9]+]], [[VAL]], [[VAR]] +; GCN: buffer_store_short [[RESULT]], +; GCN: s_endpgm + +; EG: BCNT_INT +define amdgpu_kernel void @v_ctpop_i16_add_var_inv(i16 addrspace(1)* noalias %out, i16 addrspace(1)* noalias %in, i16 %const) nounwind { + %tid = call i32 @llvm.r600.read.tidig.x() + %in.gep = getelementptr i16, i16 addrspace(1)* %in, i32 %tid + %val = load i16, i16 addrspace(1)* %in.gep, align 4 + %ctpop = call i16 @llvm.ctpop.i16(i16 %val) nounwind readnone + %add = add i16 %const, %ctpop + store i16 %add, i16 addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: {{^}}v_ctpop_i16_add_vvar_inv: +; SI: buffer_load_ushort [[VAR:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], s[{{[0-9]+:[0-9]+}}], 0 addr64 +; SI: buffer_load_ushort [[VAL:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], s[{{[0-9]+:[0-9]+}}], 0 addr64 +; SI: v_bcnt_u32_b32_e32 [[RESULT:v[0-9]+]], [[VAR]], [[VAL]] +; VI: flat_load_ushort [[VAR:v[0-9]+]], v[{{[0-9]+:[0-9]+}}] +; VI: flat_load_ushort [[VAL:v[0-9]+]], v[{{[0-9]+:[0-9]+}}] +; VI: v_bcnt_u32_b32 [[RESULT:v[0-9]+]], [[VAL]], [[VAR]] +; GCN: buffer_store_short [[RESULT]], +; GCN: s_endpgm + +; EG: BCNT_INT +define amdgpu_kernel void @v_ctpop_i16_add_vvar_inv(i16 addrspace(1)* noalias %out, i16 addrspace(1)* noalias %in, i16 addrspace(1)* noalias %constptr) nounwind { + %tid = call i32 @llvm.r600.read.tidig.x() + %in.gep = getelementptr i16, i16 addrspace(1)* %in, i32 %tid + %val = load i16, i16 addrspace(1)* %in.gep, align 4 + %ctpop = call i16 @llvm.ctpop.i16(i16 %val) nounwind readnone + %gep = getelementptr i16, i16 addrspace(1)* %constptr, i32 %tid + %const = load i16, i16 addrspace(1)* %gep, align 4 + %add = add i16 %const, %ctpop + store i16 %add, i16 addrspace(1)* %out, align 4 + ret void +} + +; FIXME: We currently disallow SALU instructions in all branches, +; but there are some cases when the should be allowed. + +; FUNC-LABEL: {{^}}ctpop_i16_in_br: +; SI: s_load_dword [[VAL:s[0-9]+]], s[{{[0-9]+:[0-9]+}}], 0xd +; VI: s_load_dword [[VAL:s[0-9]+]], s[{{[0-9]+:[0-9]+}}], 0x34 +; GCN: s_bcnt1_i32_b32 [[SRESULT:s[0-9]+]], [[VAL]] +; GCN: v_mov_b32_e32 [[RESULT:v[0-9]+]], [[SRESULT]] +; GCN: buffer_store_short [[RESULT]], +; GCN: s_endpgm +; EG: BCNT_INT +define amdgpu_kernel void @ctpop_i16_in_br(i16 addrspace(1)* %out, i16 addrspace(1)* %in, i16 %ctpop_arg, i16 %cond) { +entry: + %tmp0 = icmp eq i16 %cond, 0 + br i1 %tmp0, label %if, label %else + +if: + %tmp2 = call i16 @llvm.ctpop.i16(i16 %ctpop_arg) + br label %endif + +else: + %tmp3 = getelementptr i16, i16 addrspace(1)* %in, i16 1 + %tmp4 = load i16, i16 addrspace(1)* %tmp3 + br label %endif + +endif: + %tmp5 = phi i16 [%tmp2, %if], [%tmp4, %else] + store i16 %tmp5, i16 addrspace(1)* %out + ret void +} diff --git a/test/CodeGen/ARM/peephole-phi.mir b/test/CodeGen/ARM/peephole-phi.mir index 30343654dea1..54ae0115840b 100644 --- a/test/CodeGen/ARM/peephole-phi.mir +++ b/test/CodeGen/ARM/peephole-phi.mir @@ -65,3 +65,39 @@ body: | %4:gpr = PHI %0, %bb.1, %2, %bb.2 %5:spr = VMOVSR %4, 14, %noreg ... + +# The current implementation doesn't perform any transformations if undef +# operands are involved. +# CHECK-LABEL: name: func-undefops +# CHECK: body: | +# CHECK: bb.0: +# CHECK: Bcc %bb.2, 1, undef %cpsr +# +# CHECK: bb.1: +# CHECK: %0:gpr = VMOVRS undef %1:spr, 14, %noreg +# CHECK: B %bb.3 +# +# CHECK: bb.2: +# CHECK: %2:gpr = VMOVRS undef %3:spr, 14, %noreg +# +# CHECK: bb.3: +# CHECK: %4:gpr = PHI %0, %bb.1, %2, %bb.2 +# CHECK: %5:spr = VMOVSR %4, 14, %noreg +--- +name: func-undefops +tracksRegLiveness: true +body: | + bb.0: + Bcc %bb.2, 1, undef %cpsr + + bb.1: + %0:gpr = VMOVRS undef %1:spr, 14, %noreg + B %bb.3 + + bb.2: + %2:gpr = VMOVRS undef %3:spr, 14, %noreg + + bb.3: + %4:gpr = PHI %0, %bb.1, %2, %bb.2 + %5:spr = VMOVSR %4, 14, %noreg +... 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 diff --git a/test/CodeGen/PowerPC/convert-rr-to-ri-instrs.mir b/test/CodeGen/PowerPC/convert-rr-to-ri-instrs.mir index 67733795ed5d..f2ca07367b99 100644 --- a/test/CodeGen/PowerPC/convert-rr-to-ri-instrs.mir +++ b/test/CodeGen/PowerPC/convert-rr-to-ri-instrs.mir @@ -560,6 +560,25 @@ ret i64 %cond } + ; Function Attrs: norecurse nounwind readnone + define i64 @testRLDICLo2(i64 %a, i64 %b) local_unnamed_addr #0 { + entry: + %shr = lshr i64 %a, 11 + %and = and i64 %shr, 16777215 + %tobool = icmp eq i64 %and, 0 + %cond = select i1 %tobool, i64 %b, i64 %and + ret i64 %cond + } + + define i64 @testRLDICLo3(i64 %a, i64 %b) local_unnamed_addr #0 { + entry: + %shr = lshr i64 %a, 11 + %and = and i64 %shr, 16777215 + %tobool = icmp eq i64 %and, 0 + %cond = select i1 %tobool, i64 %b, i64 %and + ret i64 %cond + } + ; Function Attrs: norecurse nounwind readnone define zeroext i32 @testRLWINM(i32 zeroext %a) local_unnamed_addr #0 { entry: @@ -601,6 +620,15 @@ ret i32 %cond } + ; Function Attrs: norecurse nounwind readnone + define zeroext i32 @testRLWINMo2(i32 zeroext %a, i32 zeroext %b) local_unnamed_addr #0 { + entry: + %and = and i32 %a, 255 + %tobool = icmp eq i32 %and, 0 + %cond = select i1 %tobool, i32 %b, i32 %a + ret i32 %cond + } + ; Function Attrs: norecurse nounwind readnone define i64 @testRLWINM8o(i64 %a, i64 %b) local_unnamed_addr #0 { entry: @@ -3902,6 +3930,113 @@ body: | %x3 = COPY %4 BLR8 implicit %lr8, implicit %rm, implicit %x3 +... +--- +name: testRLDICLo2 +# CHECK-ALL: name: testRLDICLo2 +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +registers: + - { id: 0, class: g8rc, preferred-register: '' } + - { id: 1, class: g8rc_and_g8rc_nox0, preferred-register: '' } + - { id: 2, class: g8rc_and_g8rc_nox0, preferred-register: '' } + - { id: 3, class: crrc, preferred-register: '' } + - { id: 4, class: g8rc, preferred-register: '' } +liveins: + - { reg: '%x3', virtual-reg: '%0' } + - { reg: '%x4', virtual-reg: '%1' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 0 + adjustsStack: false + hasCalls: false + stackProtector: '' + maxCallFrameSize: 4294967295 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + savePoint: '' + restorePoint: '' +fixedStack: +stack: +constants: +body: | + bb.0.entry: + liveins: %x3, %x4 + + %1 = COPY %x4 + %0 = LI8 200 + %2 = RLDICLo %0, 61, 3, implicit-def %cr0 + ; CHECK-NOT: ANDI + ; CHECK-LATE-NOT: andi. + %3 = COPY killed %cr0 + %4 = ISEL8 %1, %2, %3.sub_eq + %x3 = COPY %4 + BLR8 implicit %lr8, implicit %rm, implicit %x3 + +... +--- +name: testRLDICLo3 +# CHECK-ALL: name: testRLDICLo3 +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +registers: + - { id: 0, class: g8rc, preferred-register: '' } + - { id: 1, class: g8rc_and_g8rc_nox0, preferred-register: '' } + - { id: 2, class: g8rc_and_g8rc_nox0, preferred-register: '' } + - { id: 3, class: crrc, preferred-register: '' } + - { id: 4, class: g8rc, preferred-register: '' } +liveins: + - { reg: '%x3', virtual-reg: '%0' } + - { reg: '%x4', virtual-reg: '%1' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 0 + adjustsStack: false + hasCalls: false + stackProtector: '' + maxCallFrameSize: 4294967295 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + savePoint: '' + restorePoint: '' +fixedStack: +stack: +constants: +body: | + bb.0.entry: + liveins: %x3, %x4 + + %1 = COPY %x4 + %0 = LI8 2 + %2 = RLDICLo %0, 32, 32, implicit-def %cr0 + ; CHECK: ANDIo8 %0, 0 + ; CHECK-LATE: li 3, 2 + ; CHECK-LATE: andi. 3, 3, 0 + %3 = COPY killed %cr0 + %4 = ISEL8 %1, %2, %3.sub_eq + %x3 = COPY %4 + BLR8 implicit %lr8, implicit %rm, implicit %x3 + ... --- name: testRLWINM @@ -4168,6 +4303,69 @@ body: | %x3 = COPY %9 BLR8 implicit %lr8, implicit %rm, implicit %x3 +... +--- +name: testRLWINMo2 +# CHECK-ALL: name: testRLWINMo2 +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +registers: + - { id: 0, class: g8rc, preferred-register: '' } + - { id: 1, class: g8rc, preferred-register: '' } + - { id: 2, class: gprc_and_gprc_nor0, preferred-register: '' } + - { id: 3, class: gprc_and_gprc_nor0, preferred-register: '' } + - { id: 4, class: gprc, preferred-register: '' } + - { id: 5, class: crrc, preferred-register: '' } + - { id: 6, class: gprc, preferred-register: '' } + - { id: 7, class: g8rc, preferred-register: '' } + - { id: 8, class: g8rc, preferred-register: '' } + - { id: 9, class: g8rc, preferred-register: '' } +liveins: + - { reg: '%x3', virtual-reg: '%0' } + - { reg: '%x4', virtual-reg: '%1' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 0 + adjustsStack: false + hasCalls: false + stackProtector: '' + maxCallFrameSize: 4294967295 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + savePoint: '' + restorePoint: '' +fixedStack: +stack: +constants: +body: | + bb.0.entry: + liveins: %x3, %x4 + + %1 = COPY %x4 + %0 = COPY %x3 + %2 = COPY %1.sub_32 + %3 = LI -22 + %4 = RLWINMo %3, 5, 24, 31, implicit-def %cr0 + ; CHECK-NOT: ANDI + ; CHECK-LATE-NOT: andi. + %5 = COPY killed %cr0 + %6 = ISEL %2, %3, %5.sub_eq + %8 = IMPLICIT_DEF + %7 = INSERT_SUBREG %8, killed %6, 1 + %9 = RLDICL killed %7, 0, 32 + %x3 = COPY %9 + BLR8 implicit %lr8, implicit %rm, implicit %x3 + ... --- name: testRLWINM8o diff --git a/test/CodeGen/PowerPC/pr35402.ll b/test/CodeGen/PowerPC/pr35402.ll new file mode 100644 index 000000000000..06e6d963b13f --- /dev/null +++ b/test/CodeGen/PowerPC/pr35402.ll @@ -0,0 +1,18 @@ +; RUN: llc -O2 < %s | FileCheck %s +target triple = "powerpc64le-linux-gnu" + +define void @test(i8* %p, i64 %data) { +entry: + %0 = tail call i64 @llvm.bswap.i64(i64 %data) + %ptr = bitcast i8* %p to i48* + %val = trunc i64 %0 to i48 + store i48 %val, i48* %ptr, align 1 + ret void + +; CHECK: sth +; CHECK: stw +; CHECK-NOT: stdbrx + +} + +declare i64 @llvm.bswap.i64(i64) diff --git a/test/CodeGen/Thumb/PR36658.mir b/test/CodeGen/Thumb/PR36658.mir new file mode 100644 index 000000000000..15a3c7f407b1 --- /dev/null +++ b/test/CodeGen/Thumb/PR36658.mir @@ -0,0 +1,359 @@ +# REQUIRES: asserts +# RUN: llc -run-pass arm-cp-islands %s -o - | FileCheck %s +# +# This is a reduced test made to expose a bug in +# ARMConstantIslandPass in Thumb1 mode, see PR36658. + +# Verify optimized JT code uses TBB instructions. +# CHECK-LABEL: bb.7.entry: +# CHECK: tTBB_JT %pc, killed %r2, %jump-table.1, 0 +# CHECK-LABEL: bb.8: +# CHECK: JUMPTABLE_TBB 0, %jump-table.1, 44 + +# CHECK-LABEL: bb.11.entry: +# CHECK: %r1 = tMOVSr %r0, implicit-def dead %cpsr +# CHECK: tTBB_JT %pc, killed %r2, %jump-table.0, 1 +# CHECK-LABEL: bb.12: +# CHECK: JUMPTABLE_TBB 1, %jump-table.0, 44 + +--- | + ; ModuleID = 'PR36658.ll' + source_filename = "PR36658.ll" + target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" + target triple = "thumbv5e-none-linux-gnueabi" + + declare i32 @foo1(...) + + declare i32 @foo2(i32) + + declare i32 @foo3(i32*) + + ; Function Attrs: nounwind optsize + define internal fastcc i32 @foo4(i32* nocapture %ignore_ptr) #0 { + entry: + %call = tail call i32 @foo3(i32* undef) + switch i32 %call, label %sw.epilog [ + i32 120, label %sw.bb + i32 48, label %sw.bb73 + i32 49, label %sw.bb73 + i32 50, label %sw.bb73 + i32 51, label %sw.bb73 + i32 52, label %sw.bb73 + i32 53, label %sw.bb73 + i32 54, label %sw.bb73 + i32 55, label %sw.bb73 + i32 92, label %cleanup + i32 39, label %cleanup + i32 34, label %cleanup + i32 10, label %sw.bb91 + i32 110, label %sw.bb93 + i32 116, label %sw.bb94 + i32 114, label %sw.bb95 + i32 102, label %sw.bb96 + i32 98, label %sw.bb97 + i32 97, label %sw.bb98 + i32 118, label %sw.bb106 + i32 101, label %sw.bb107 + i32 69, label %sw.bb107 + i32 63, label %cleanup + ] + + sw.bb: ; preds = %entry + br label %while.cond + + while.cond: ; preds = %while.cond, %sw.bb + %call5 = tail call i32 @foo3(i32* null) + br label %while.cond + + sw.bb73: ; preds = %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry + %0 = and i32 %call, -8 + %1 = icmp eq i32 %0, 48 + br i1 %1, label %while.body83.preheader, label %while.end88 + + while.body83.preheader: ; preds = %sw.bb73 + br label %while.body83 + + while.body83: ; preds = %while.body83.preheader, %while.body83 + %call87 = tail call i32 @foo3(i32* null) + br label %while.body83 + + while.end88: ; preds = %sw.bb73 + %call89 = tail call i32 @foo2(i32 %call) + unreachable + + sw.bb91: ; preds = %entry + store i32 1, i32* %ignore_ptr, align 4 + br label %cleanup + + sw.bb93: ; preds = %entry + br label %cleanup + + sw.bb94: ; preds = %entry + br label %cleanup + + sw.bb95: ; preds = %entry + br label %cleanup + + sw.bb96: ; preds = %entry + br label %cleanup + + sw.bb97: ; preds = %entry + br label %cleanup + + sw.bb98: ; preds = %entry + br label %cleanup + + sw.bb106: ; preds = %entry + br label %cleanup + + sw.bb107: ; preds = %entry, %entry + br i1 undef, label %cleanup, label %if.then109 + + if.then109: ; preds = %sw.bb107 + %call110 = tail call i32 bitcast (i32 (...)* @foo1 to i32 (i8*, i32)*)(i8* undef, i32 %call) + unreachable + + sw.epilog: ; preds = %entry + %call.off = add i32 %call, -32 + unreachable + + cleanup: ; preds = %sw.bb107, %sw.bb106, %sw.bb98, %sw.bb97, %sw.bb96, %sw.bb95, %sw.bb94, %sw.bb93, %sw.bb91, %entry, %entry, %entry, %entry + %retval.0 = phi i32 [ 11, %sw.bb106 ], [ 7, %sw.bb98 ], [ 8, %sw.bb97 ], [ 12, %sw.bb96 ], [ 13, %sw.bb95 ], [ 9, %sw.bb94 ], [ 10, %sw.bb93 ], [ 0, %sw.bb91 ], [ %call, %entry ], [ %call, %entry ], [ %call, %entry ], [ 27, %sw.bb107 ], [ %call, %entry ] + ret i32 %retval.0 + } + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) #1 + + attributes #0 = { nounwind optsize } + attributes #1 = { nounwind } + +... +--- +name: foo4 +alignment: 1 +tracksRegLiveness: true +liveins: + - { reg: '%r0' } +frameInfo: + stackSize: 8 + maxAlignment: 4 + adjustsStack: true + hasCalls: true + maxCallFrameSize: 0 +stack: + - { id: 0, type: spill-slot, offset: -4, size: 4, alignment: 4, stack-id: 0, + callee-saved-register: '%lr', callee-saved-restored: false } + - { id: 1, type: spill-slot, offset: -8, size: 4, alignment: 4, stack-id: 0, + callee-saved-register: '%r4' } +jumpTable: + kind: inline + entries: + - id: 0 + blocks: [ '%bb.28', '%bb.26', '%bb.26', '%bb.26', '%bb.26', + '%bb.24', '%bb.23', '%bb.26', '%bb.26', '%bb.12', + '%bb.22' ] + - id: 1 + blocks: [ '%bb.19', '%bb.26', '%bb.26', '%bb.26', '%bb.21', + '%bb.26', '%bb.20', '%bb.26', '%bb.25', '%bb.26', + '%bb.15' ] +body: | + bb.0.entry: + successors: %bb.1(0x42c8590b), %bb.9(0x3d37a6f5) + liveins: %r0, %r4, %lr + + frame-setup tPUSH 14, %noreg, killed %r4, killed %lr, implicit-def %sp, implicit %sp + frame-setup CFI_INSTRUCTION def_cfa_offset 8 + frame-setup CFI_INSTRUCTION offset %lr, -4 + frame-setup CFI_INSTRUCTION offset %r4, -8 + %r4 = tMOVSr %r0, implicit-def dead %cpsr + tBL 14, %noreg, @foo3, csr_aapcs, implicit-def dead %lr, implicit %sp, implicit undef %r0, implicit-def %sp, implicit-def %r0 + %r1 = tMOVSr %r0, implicit-def dead %cpsr + tCMPi8 %r0, 68, 14, %noreg, implicit-def %cpsr + tBcc %bb.9, 12, killed %cpsr + + bb.1.entry: + successors: %bb.2(0x20000000), %bb.7(0x60000000) + liveins: %r0, %r1, %r4 + + tCMPi8 renamable %r1, 47, 14, %noreg, implicit-def %cpsr + tBcc %bb.2, 13, killed %cpsr + + bb.7.entry: + successors: %bb.16(0x71c71c72), %bb.8(0x0e38e38e) + liveins: %r0, %r1 + + %r2 = tMOVSr %r1, implicit-def dead %cpsr + renamable %r2, dead %cpsr = tSUBi8 killed renamable %r2, 48, 14, %noreg + tCMPi8 killed renamable %r2, 8, 14, %noreg, implicit-def %cpsr + tBcc %bb.8, 2, killed %cpsr + + bb.16.sw.bb73: + successors: %bb.17(0x7fffffff), %bb.18(0x00000001) + liveins: %r0, %r1 + + renamable %r2, dead %cpsr = tMOVi8 7, 14, %noreg + renamable %r1, dead %cpsr = tBIC killed renamable %r1, killed renamable %r2, 14, %noreg + tCMPi8 killed renamable %r1, 48, 14, %noreg, implicit-def %cpsr + tBcc %bb.18, 1, killed %cpsr + + bb.17.while.body83: + renamable %r0, dead %cpsr = tMOVi8 0, 14, %noreg + tBL 14, %noreg, @foo3, csr_aapcs, implicit-def dead %lr, implicit %sp, implicit %r0, implicit-def %sp, implicit-def dead %r0 + tB %bb.17, 14, %noreg + + bb.9.entry: + successors: %bb.10(0x45d1745d), %bb.29(0x3a2e8ba3) + liveins: %r0, %r1 + + %r2 = tMOVSr %r1, implicit-def dead %cpsr + renamable %r2, dead %cpsr = tSUBi8 killed renamable %r2, 92, 14, %noreg + tCMPi8 renamable %r2, 10, 14, %noreg, implicit-def %cpsr + tBcc %bb.29, 9, killed %cpsr + + bb.10.entry: + successors: %bb.11(0x15555555), %bb.14(0x6aaaaaab) + liveins: %r0, %r1 + + %r2 = tMOVSr %r1, implicit-def dead %cpsr + renamable %r2, dead %cpsr = tSUBi8 killed renamable %r2, 110, 14, %noreg + tCMPi8 renamable %r2, 10, 14, %noreg, implicit-def %cpsr + tBcc %bb.11, 8, killed %cpsr + + bb.14.entry: + successors: %bb.19(0x1999999a), %bb.26(0x00000000), %bb.21(0x1999999a), %bb.20(0x1999999a), %bb.25(0x1999999a), %bb.15(0x1999999a) + liveins: %r2 + + renamable %r0, dead %cpsr = tLSLri killed renamable %r2, 2, 14, %noreg + renamable %r1 = tLEApcrelJT %jump-table.1, 14, %noreg + renamable %r0 = tLDRr killed renamable %r1, killed renamable %r0, 14, %noreg :: (load 4 from jump-table) + tBR_JTr killed renamable %r0, %jump-table.1 + + bb.19.sw.bb93: + renamable %r1, dead %cpsr = tMOVi8 10, 14, %noreg + tB %bb.28, 14, %noreg + + bb.15.while.cond: + renamable %r0, dead %cpsr = tMOVi8 0, 14, %noreg + tBL 14, %noreg, @foo3, csr_aapcs, implicit-def dead %lr, implicit %sp, implicit %r0, implicit-def %sp, implicit-def dead %r0 + tB %bb.15, 14, %noreg + + bb.29.entry: + successors: %bb.28(0x1999999a), %bb.26(0x00000000), %bb.24(0x1999999a), %bb.23(0x1999999a), %bb.12(0x1999999a), %bb.22(0x1999999a) + liveins: %r0, %r2 + + renamable %r1, dead %cpsr = tLSLri killed renamable %r2, 2, 14, %noreg + renamable %r2 = tLEApcrelJT %jump-table.0, 14, %noreg + renamable %r2 = tLDRr killed renamable %r2, killed renamable %r1, 14, %noreg :: (load 4 from jump-table) + %r1 = tMOVSr %r0, implicit-def dead %cpsr + tBR_JTr killed renamable %r2, %jump-table.0 + + bb.24.sw.bb98: + renamable %r1, dead %cpsr = tMOVi8 7, 14, %noreg + tB %bb.28, 14, %noreg + + bb.2.entry: + successors: %bb.27(0x2aaaaaab), %bb.3(0x55555555) + liveins: %r0, %r1, %r4 + + tCMPi8 renamable %r1, 10, 14, %noreg, implicit-def %cpsr + tBcc %bb.27, 0, killed %cpsr + + bb.3.entry: + successors: %bb.4, %bb.5 + liveins: %r0, %r1 + + tCMPi8 renamable %r1, 34, 14, %noreg, implicit-def %cpsr + tBcc %bb.5, 1, killed %cpsr + + bb.4: + liveins: %r0 + + %r1 = tMOVSr killed %r0, implicit-def dead %cpsr + tB %bb.28, 14, %noreg + + bb.25.sw.bb106: + renamable %r1, dead %cpsr = tMOVi8 11, 14, %noreg + tB %bb.28, 14, %noreg + + bb.23.sw.bb97: + renamable %r1, dead %cpsr = tMOVi8 8, 14, %noreg + tB %bb.28, 14, %noreg + + bb.27.sw.bb91: + liveins: %r4 + + renamable %r0, dead %cpsr = tMOVi8 1, 14, %noreg + tSTRi killed renamable %r0, killed renamable %r4, 0, 14, %noreg :: (store 4 into %ir.ignore_ptr) + renamable %r1, dead %cpsr = tMOVi8 0, 14, %noreg + tB %bb.28, 14, %noreg + + bb.21.sw.bb95: + renamable %r1, dead %cpsr = tMOVi8 13, 14, %noreg + tB %bb.28, 14, %noreg + + bb.20.sw.bb94: + renamable %r1, dead %cpsr = tMOVi8 9, 14, %noreg + tB %bb.28, 14, %noreg + + bb.5.entry: + liveins: %r0, %r1 + + tCMPi8 killed renamable %r1, 39, 14, %noreg, implicit-def %cpsr + tB %bb.6, 14, %noreg + + bb.11.entry: + successors: %bb.12(0x80000000), %bb.26(0x00000000) + liveins: %r0, %r1 + + tCMPi8 killed renamable %r1, 69, 14, %noreg, implicit-def %cpsr + tBcc %bb.26, 1, killed %cpsr + + bb.12.sw.bb107: + successors: %bb.28(0x7fffffff), %bb.13(0x00000001) + liveins: %r0 + + renamable %r1, dead %cpsr = tMOVi8 27, 14, %noreg + renamable %r2, dead %cpsr = tMOVi8 0, 14, %noreg + tCMPi8 killed renamable %r2, 0, 14, %noreg, implicit-def %cpsr + tBcc %bb.28, 1, killed %cpsr + + bb.13.if.then109: + successors: + liveins: %r0 + + %r1 = tMOVSr killed %r0, implicit-def dead %cpsr + tBL 14, %noreg, @foo1, csr_aapcs, implicit-def dead %lr, implicit %sp, implicit undef %r0, implicit %r1, implicit-def %sp, implicit-def dead %r0 + + bb.8.entry: + liveins: %r0, %r1 + + tCMPi8 killed renamable %r1, 63, 14, %noreg, implicit-def %cpsr + + bb.6.entry: + successors: %bb.28(0x80000000), %bb.26(0x00000000) + liveins: %cpsr, %r0 + + tPUSH 14, %noreg, killed %r0, implicit-def %sp, implicit %sp + tPOP 14, %noreg, def %r1, implicit-def %sp, implicit %sp + tBcc %bb.28, 0, killed %cpsr + + bb.26.sw.epilog: + successors: + + + bb.22.sw.bb96: + renamable %r1, dead %cpsr = tMOVi8 12, 14, %noreg + + bb.28.cleanup: + liveins: %r1 + + %r0 = tMOVSr killed %r1, implicit-def dead %cpsr + tPOP_RET 14, %noreg, def %r4, def %pc, implicit-def %sp, implicit %sp, implicit %r0 + + bb.18.while.end88: + liveins: %r0 + + tBL 14, %noreg, @foo2, csr_aapcs, implicit-def dead %lr, implicit %sp, implicit %r0, implicit-def %sp, implicit-def dead %r0 + +... diff --git a/test/DebugInfo/X86/live-debug-vars-discard-invalid.mir b/test/DebugInfo/X86/live-debug-vars-discard-invalid.mir index abc21bc6ac90..51045f45b217 100644 --- a/test/DebugInfo/X86/live-debug-vars-discard-invalid.mir +++ b/test/DebugInfo/X86/live-debug-vars-discard-invalid.mir @@ -64,7 +64,7 @@ body: | bb.1: ; This DBG_VALUE will be discarded (use before def of %0). - DBG_VALUE debug-use %0, debug-use $noreg, !18, !DIExpression(), debug-location !25 + DBG_VALUE debug-use %0, debug-use %noreg, !18, !DIExpression(), debug-location !25 %0:gr64 = IMPLICIT_DEF %0:gr64 = IMPLICIT_DEF %0:gr64 = IMPLICIT_DEF @@ -72,32 +72,32 @@ body: | bb.2: ; This DBG_VALUE will be discarded (%1 is defined earlier, but it is not live in, so we do not know where %1 is stored). - DBG_VALUE debug-use %1, debug-use $noreg, !18, !DIExpression(), debug-location !25 + DBG_VALUE debug-use %1, debug-use %noreg, !18, !DIExpression(), debug-location !25 %1:gr64 = IMPLICIT_DEF %1:gr64 = IMPLICIT_DEF %1:gr64 = IMPLICIT_DEF %1:gr64 = IMPLICIT_DEF ; This DBG_VALUE is kept, even if %1 is dead, it was defined in the prev instruction, ; so the value should be available for as long as the register allocated to %1 is live. - DBG_VALUE debug-use %1, debug-use $noreg, !18, !DIExpression(), debug-location !25 + DBG_VALUE debug-use %1, debug-use %noreg, !18, !DIExpression(), debug-location !25 bb.3: %1:gr64 = IMPLICIT_DEF - DBG_VALUE 0, debug-use $noreg, !23, !DIExpression(), debug-location !25 + DBG_VALUE 0, debug-use %noreg, !23, !DIExpression(), debug-location !25 ; This DBG_VALUE is kept, even if %1 is dead, it was defined in the prev non-dbg instruction, ; so the value should be available for as long as the register allocated to %1 is live. - DBG_VALUE debug-use %1, debug-use $noreg, !18, !DIExpression(), debug-location !25 + DBG_VALUE debug-use %1, debug-use %noreg, !18, !DIExpression(), debug-location !25 bb.4: ; All DBG_VALUEs here should survive. %2 is livein as it was defined in bb.0, and it has use/def in the BTS64rr instruction. - DBG_VALUE debug-use %2, debug-use $noreg, !18, !DIExpression(), debug-location !25 - %2:gr64 = BTS64rr %2, 0, implicit-def $eflags - DBG_VALUE 0, debug-use $noreg, !23, !DIExpression(), debug-location !25 - DBG_VALUE debug-use %2, debug-use $noreg, !18, !DIExpression(), debug-location !25 - %2:gr64 = BTS64rr %2, 0, implicit-def $eflags - DBG_VALUE debug-use %2, debug-use $noreg, !18, !DIExpression(), debug-location !25 - %2:gr64 = BTS64rr %2, 0, implicit-def $eflags - DBG_VALUE debug-use %2, debug-use $noreg, !18, !DIExpression(), debug-location !25 + DBG_VALUE debug-use %2, debug-use %noreg, !18, !DIExpression(), debug-location !25 + %2:gr64 = BTS64rr %2, 0, implicit-def %eflags + DBG_VALUE 0, debug-use %noreg, !23, !DIExpression(), debug-location !25 + DBG_VALUE debug-use %2, debug-use %noreg, !18, !DIExpression(), debug-location !25 + %2:gr64 = BTS64rr %2, 0, implicit-def %eflags + DBG_VALUE debug-use %2, debug-use %noreg, !18, !DIExpression(), debug-location !25 + %2:gr64 = BTS64rr %2, 0, implicit-def %eflags + DBG_VALUE debug-use %2, debug-use %noreg, !18, !DIExpression(), debug-location !25 bb.5: RET 0, debug-location !32 @@ -107,35 +107,35 @@ body: | # CHECK-LABEL: bb.1: ## After solving https://bugs.llvm.org/show_bug.cgi?id=36579 we expect to get a -## DBG_VALUE debug-use $noreg +## DBG_VALUE debug-use %noreg ## here. # CHECK-NOT: DBG_VALUE # CHECK-LABEL: bb.2: ## After solving https://bugs.llvm.org/show_bug.cgi?id=36579 we expect to get a -## DBG_VALUE debug-use $noreg +## DBG_VALUE debug-use %noreg ## here. # CHECK-NOT: DBG_VALUE -# CHECK: dead renamable $rcx = IMPLICIT_DEF -# CHECK-NEXT: dead renamable $rcx = IMPLICIT_DEF -# CHECK-NEXT: dead renamable $rcx = IMPLICIT_DEF -# CHECK-NEXT: dead renamable $rcx = IMPLICIT_DEF -# CHECK-NEXT: DBG_VALUE debug-use $rcx, debug-use $noreg, !18, !DIExpression() +# CHECK: dead renamable %rcx = IMPLICIT_DEF +# CHECK-NEXT: dead renamable %rcx = IMPLICIT_DEF +# CHECK-NEXT: dead renamable %rcx = IMPLICIT_DEF +# CHECK-NEXT: dead renamable %rcx = IMPLICIT_DEF +# CHECK-NEXT: DBG_VALUE debug-use %rcx, debug-use %noreg, !18, !DIExpression() # CHECK-LABEL: bb.3: -# CHECK: dead renamable $rcx = IMPLICIT_DEF -# CHECK-NEXT: DBG_VALUE 0, debug-use $noreg, !23, !DIExpression() -# CHECK-NEXT: DBG_VALUE debug-use $rcx, debug-use $noreg, !18, !DIExpression() +# CHECK: dead renamable %rcx = IMPLICIT_DEF +# CHECK-NEXT: DBG_VALUE 0, debug-use %noreg, !23, !DIExpression() +# CHECK-NEXT: DBG_VALUE debug-use %rcx, debug-use %noreg, !18, !DIExpression() # CHECK-LABEL: bb.4: -# CHECK: liveins: $rax -# CHECK: DBG_VALUE debug-use $rax, debug-use $noreg, !18, !DIExpression() -# CHECK-NEXT: renamable $rax = BTS64rr killed renamable $rax, 0, implicit-def $eflags -# CHECK-NEXT: DBG_VALUE 0, debug-use $noreg, !23, !DIExpression() -# CHECK-NEXT: DBG_VALUE debug-use $rax, debug-use $noreg, !18, !DIExpression() -# CHECK-NEXT: renamable $rax = BTS64rr killed renamable $rax, 0, implicit-def $eflags -# CHECK-NEXT: DBG_VALUE debug-use $rax, debug-use $noreg, !18, !DIExpression() -# CHECK-NEXT: dead renamable $rax = BTS64rr killed renamable $rax, 0, implicit-def $eflags +# CHECK: liveins: %rax +# CHECK: DBG_VALUE debug-use %rax, debug-use %noreg, !18, !DIExpression() +# CHECK-NEXT: renamable %rax = BTS64rr killed renamable %rax, 0, implicit-def %eflags +# CHECK-NEXT: DBG_VALUE 0, debug-use %noreg, !23, !DIExpression() +# CHECK-NEXT: DBG_VALUE debug-use %rax, debug-use %noreg, !18, !DIExpression() +# CHECK-NEXT: renamable %rax = BTS64rr killed renamable %rax, 0, implicit-def %eflags +# CHECK-NEXT: DBG_VALUE debug-use %rax, debug-use %noreg, !18, !DIExpression() +# CHECK-NEXT: dead renamable %rax = BTS64rr killed renamable %rax, 0, implicit-def %eflags # CHECK-LABEL: bb.5: # CHECK-NEXT: RET 0 diff --git a/test/Transforms/ArgumentPromotion/musttail.ll b/test/Transforms/ArgumentPromotion/musttail.ll new file mode 100644 index 000000000000..aa1871168693 --- /dev/null +++ b/test/Transforms/ArgumentPromotion/musttail.ll @@ -0,0 +1,45 @@ +; RUN: opt < %s -argpromotion -S | FileCheck %s +; PR36543 + +; Don't promote arguments of musttail callee + +%T = type { i32, i32, i32, i32 } + +; CHECK-LABEL: define internal i32 @test(%T* %p) +define internal i32 @test(%T* %p) { + %a.gep = getelementptr %T, %T* %p, i64 0, i32 3 + %b.gep = getelementptr %T, %T* %p, i64 0, i32 2 + %a = load i32, i32* %a.gep + %b = load i32, i32* %b.gep + %v = add i32 %a, %b + ret i32 %v +} + +; CHECK-LABEL: define i32 @caller(%T* %p) +define i32 @caller(%T* %p) { + %v = musttail call i32 @test(%T* %p) + ret i32 %v +} + +; Don't promote arguments of musttail caller + +define i32 @foo(%T* %p, i32 %v) { + ret i32 0 +} + +; CHECK-LABEL: define internal i32 @test2(%T* %p, i32 %p2) +define internal i32 @test2(%T* %p, i32 %p2) { + %a.gep = getelementptr %T, %T* %p, i64 0, i32 3 + %b.gep = getelementptr %T, %T* %p, i64 0, i32 2 + %a = load i32, i32* %a.gep + %b = load i32, i32* %b.gep + %v = add i32 %a, %b + %ca = musttail call i32 @foo(%T* undef, i32 %v) + ret i32 %ca +} + +; CHECK-LABEL: define i32 @caller2(%T* %g) +define i32 @caller2(%T* %g) { + %v = call i32 @test2(%T* %g, i32 0) + ret i32 %v +} diff --git a/test/Transforms/CallSiteSplitting/musttail.ll b/test/Transforms/CallSiteSplitting/musttail.ll new file mode 100644 index 000000000000..97548501cd5c --- /dev/null +++ b/test/Transforms/CallSiteSplitting/musttail.ll @@ -0,0 +1,109 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -callsite-splitting -S | FileCheck %s + +define i8* @caller(i8* %a, i8* %b) { +; CHECK-LABEL: @caller( +; CHECK-NEXT: Top: +; CHECK-NEXT: [[C:%.*]] = icmp eq i8* [[A:%.*]], null +; CHECK-NEXT: br i1 [[C]], label [[TAIL_PREDBB1_SPLIT:%.*]], label [[TBB:%.*]] +; CHECK: TBB: +; CHECK-NEXT: [[C2:%.*]] = icmp eq i8* [[B:%.*]], null +; CHECK-NEXT: br i1 [[C2]], label [[TAIL_PREDBB2_SPLIT:%.*]], label [[END:%.*]] +; CHECK: Tail.predBB1.split: +; CHECK-NEXT: [[TMP0:%.*]] = musttail call i8* @callee(i8* null, i8* [[B]]) +; CHECK-NEXT: [[CB1:%.*]] = bitcast i8* [[TMP0]] to i8* +; CHECK-NEXT: ret i8* [[CB1]] +; CHECK: Tail.predBB2.split: +; CHECK-NEXT: [[TMP1:%.*]] = musttail call i8* @callee(i8* nonnull [[A]], i8* null) +; CHECK-NEXT: [[CB2:%.*]] = bitcast i8* [[TMP1]] to i8* +; CHECK-NEXT: ret i8* [[CB2]] +; CHECK: End: +; CHECK-NEXT: ret i8* null +; +Top: + %c = icmp eq i8* %a, null + br i1 %c, label %Tail, label %TBB +TBB: + %c2 = icmp eq i8* %b, null + br i1 %c2, label %Tail, label %End +Tail: + %ca = musttail call i8* @callee(i8* %a, i8* %b) + %cb = bitcast i8* %ca to i8* + ret i8* %cb +End: + ret i8* null +} + +define i8* @callee(i8* %a, i8* %b) noinline { +; CHECK-LABEL: define i8* @callee( +; CHECK-NEXT: ret i8* [[A:%.*]] +; + ret i8* %a +} + +define i8* @no_cast_caller(i8* %a, i8* %b) { +; CHECK-LABEL: @no_cast_caller( +; CHECK-NEXT: Top: +; CHECK-NEXT: [[C:%.*]] = icmp eq i8* [[A:%.*]], null +; CHECK-NEXT: br i1 [[C]], label [[TAIL_PREDBB1_SPLIT:%.*]], label [[TBB:%.*]] +; CHECK: TBB: +; CHECK-NEXT: [[C2:%.*]] = icmp eq i8* [[B:%.*]], null +; CHECK-NEXT: br i1 [[C2]], label [[TAIL_PREDBB2_SPLIT:%.*]], label [[END:%.*]] +; CHECK: Tail.predBB1.split: +; CHECK-NEXT: [[TMP0:%.*]] = musttail call i8* @callee(i8* null, i8* [[B]]) +; CHECK-NEXT: ret i8* [[TMP0]] +; CHECK: Tail.predBB2.split: +; CHECK-NEXT: [[TMP1:%.*]] = musttail call i8* @callee(i8* nonnull [[A]], i8* null) +; CHECK-NEXT: ret i8* [[TMP1]] +; CHECK: End: +; CHECK-NEXT: ret i8* null +; +Top: + %c = icmp eq i8* %a, null + br i1 %c, label %Tail, label %TBB +TBB: + %c2 = icmp eq i8* %b, null + br i1 %c2, label %Tail, label %End +Tail: + %ca = musttail call i8* @callee(i8* %a, i8* %b) + ret i8* %ca +End: + ret i8* null +} + +define void @void_caller(i8* %a, i8* %b) { +; CHECK-LABEL: @void_caller( +; CHECK-NEXT: Top: +; CHECK-NEXT: [[C:%.*]] = icmp eq i8* [[A:%.*]], null +; CHECK-NEXT: br i1 [[C]], label [[TAIL_PREDBB1_SPLIT:%.*]], label [[TBB:%.*]] +; CHECK: TBB: +; CHECK-NEXT: [[C2:%.*]] = icmp eq i8* [[B:%.*]], null +; CHECK-NEXT: br i1 [[C2]], label [[TAIL_PREDBB2_SPLIT:%.*]], label [[END:%.*]] +; CHECK: Tail.predBB1.split: +; CHECK-NEXT: musttail call void @void_callee(i8* null, i8* [[B]]) +; CHECK-NEXT: ret void +; CHECK: Tail.predBB2.split: +; CHECK-NEXT: musttail call void @void_callee(i8* nonnull [[A]], i8* null) +; CHECK-NEXT: ret void +; CHECK: End: +; CHECK-NEXT: ret void +; +Top: + %c = icmp eq i8* %a, null + br i1 %c, label %Tail, label %TBB +TBB: + %c2 = icmp eq i8* %b, null + br i1 %c2, label %Tail, label %End +Tail: + musttail call void @void_callee(i8* %a, i8* %b) + ret void +End: + ret void +} + +define void @void_callee(i8* %a, i8* %b) noinline { +; CHECK-LABEL: define void @void_callee( +; CHECK-NEXT: ret void +; + ret void +} diff --git a/test/Transforms/GlobalOpt/musttail_cc.ll b/test/Transforms/GlobalOpt/musttail_cc.ll new file mode 100644 index 000000000000..fc927ea91dd8 --- /dev/null +++ b/test/Transforms/GlobalOpt/musttail_cc.ll @@ -0,0 +1,34 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; PR36546 + +; Check that musttail callee preserves its calling convention + +define i32 @test(i32 %a) { + ; CHECK: %ca = musttail call i32 @foo(i32 %a) + %ca = musttail call i32 @foo(i32 %a) + ret i32 %ca +} + +; CHECK-LABEL: define internal i32 @foo(i32 %a) +define internal i32 @foo(i32 %a) { + ret i32 %a +} + +; Check that musttail caller preserves its calling convention + +define i32 @test2(i32 %a) { + %ca = call i32 @foo1(i32 %a) + ret i32 %ca +} + +; CHECK-LABEL: define internal i32 @foo1(i32 %a) +define internal i32 @foo1(i32 %a) { + ; CHECK: %ca = musttail call i32 @foo2(i32 %a) + %ca = musttail call i32 @foo2(i32 %a) + ret i32 %ca +} + +; CHECK-LABEL: define internal i32 @foo2(i32 %a) +define internal i32 @foo2(i32 %a) { + ret i32 %a +} diff --git a/test/Transforms/IPConstantProp/musttail-call.ll b/test/Transforms/IPConstantProp/musttail-call.ll new file mode 100644 index 000000000000..f02f6992a70d --- /dev/null +++ b/test/Transforms/IPConstantProp/musttail-call.ll @@ -0,0 +1,58 @@ +; RUN: opt < %s -ipsccp -S | FileCheck %s +; PR36485 +; musttail call result can\'t be replaced with a constant, unless the call +; can be removed + +declare i32 @external() + +define i8* @start(i8 %v) { + %c1 = icmp eq i8 %v, 0 + br i1 %c1, label %true, label %false +true: + ; CHECK: %ca = musttail call i8* @side_effects(i8 %v) + ; CHECK: ret i8* %ca + %ca = musttail call i8* @side_effects(i8 %v) + ret i8* %ca +false: + %c2 = icmp eq i8 %v, 1 + br i1 %c2, label %c2_true, label %c2_false +c2_true: + ; CHECK: %ca1 = musttail call i8* @no_side_effects(i8 %v) + ; CHECK: ret i8* %ca1 + %ca1 = musttail call i8* @no_side_effects(i8 %v) + ret i8* %ca1 +c2_false: + ; CHECK: %ca2 = musttail call i8* @dont_zap_me(i8 %v) + ; CHECK: ret i8* %ca2 + %ca2 = musttail call i8* @dont_zap_me(i8 %v) + ret i8* %ca2 +} + +define internal i8* @side_effects(i8 %v) { + %i1 = call i32 @external() + + ; since this goes back to `start` the SCPP should be see that the return value + ; is always `null`. + ; The call can't be removed due to `external` call above, though. + + ; CHECK: %ca = musttail call i8* @start(i8 %v) + %ca = musttail call i8* @start(i8 %v) + + ; Thus the result must be returned anyway + ; CHECK: ret i8* %ca + ret i8* %ca +} + +define internal i8* @no_side_effects(i8 %v) readonly nounwind { + ; CHECK: ret i8* null + ret i8* null +} + +define internal i8* @dont_zap_me(i8 %v) { + %i1 = call i32 @external() + + ; The call to this function cannot be removed due to side effects. Thus the + ; return value should stay as it is, and should not be zapped. + ; CHECK: ret i8* null + ret i8* null +} diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt index 25f99cec9788..335c8c3fbb7f 100644 --- a/tools/llvm-config/CMakeLists.txt +++ b/tools/llvm-config/CMakeLists.txt @@ -9,8 +9,9 @@ add_llvm_tool(llvm-config ) # Compute the substitution values for various items. -get_property(LLVM_SYSTEM_LIBS_LIST TARGET LLVMSupport PROPERTY LLVM_SYSTEM_LIBS) -foreach(l ${LLVM_SYSTEM_LIBS_LIST}) +get_property(SUPPORT_SYSTEM_LIBS TARGET LLVMSupport PROPERTY LLVM_SYSTEM_LIBS) +get_property(WINDOWSMANIFEST_SYSTEM_LIBS TARGET LLVMWindowsManifest PROPERTY LLVM_SYSTEM_LIBS) +foreach(l ${SUPPORT_SYSTEM_LIBS} ${WINDOWSMANIFEST_SYSTEM_LIBS}) if(MSVC) set(SYSTEM_LIBS ${SYSTEM_LIBS} "${l}.lib") else()