Index: include/llvm/CodeGen/MachineInstr.h =================================================================== --- include/llvm/CodeGen/MachineInstr.h +++ include/llvm/CodeGen/MachineInstr.h @@ -16,6 +16,7 @@ #define LLVM_CODEGEN_MACHINEINSTR_H #include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerSumType.h" #include "llvm/ADT/ilist.h" #include "llvm/ADT/ilist_node.h" @@ -1361,6 +1362,11 @@ void addRegisterDefined(unsigned Reg, const TargetRegisterInfo *RegInfo = nullptr); + /// We have determined that MI uses a register. Make sure there is an operand + /// using Reg. + void addRegisterUse(unsigned Reg, + const TargetRegisterInfo *RegInfo = nullptr); + /// Mark every physreg used by this instruction as /// dead except those in the UsedRegs list. /// @@ -1369,6 +1375,12 @@ void setPhysRegsDeadExcept(ArrayRef UsedRegs, const TargetRegisterInfo &TRI); + /// Mark every physreg used in implicit operands for this instruction as dead + /// as some of them will be added later than others if 'hasPostISelHook' is + /// true. Also keep track of them so the dead flag can be removed upon use by + /// some other instruction. + void setImplicitRegsDead(DenseMap &ImplicitRegs); + /// Return true if it is safe to move this instruction. If /// SawStore is set to true, it means that there is a store (or call) between /// the instruction's location and its intended destination. Index: include/llvm/CodeGen/TargetLowering.h =================================================================== --- include/llvm/CodeGen/TargetLowering.h +++ include/llvm/CodeGen/TargetLowering.h @@ -4017,6 +4017,17 @@ virtual void AdjustInstrPostInstrSelection(MachineInstr &MI, SDNode *Node) const; + /// This method should be implemented by targets if they add any new operands + /// in AdjustInstrPostInstrSelection controled by 'hasPostISelHook' flag. They + /// might have been marked as dead regardless of their later use and should be + /// adjusted. ImplicitRegs keeps track of previously added operands and should + /// be checked against operands of current instruction. Afterwards they should + /// be marked as dead and added to ImplicitRegs. + virtual void + AdjustImplicitRegsDead(MachineInstr &MI, + DenseMap &ImplicitRegs, + const MCInstrDesc &II) const; + /// If this function returns true, SelectionDAGBuilder emits a /// LOAD_STACK_GUARD node when it is lowering Intrinsic::stackprotector. virtual bool useLoadStackGuardNode() const { Index: lib/CodeGen/LiveVariables.cpp =================================================================== --- lib/CodeGen/LiveVariables.cpp +++ lib/CodeGen/LiveVariables.cpp @@ -528,11 +528,6 @@ UseRegs.push_back(MOReg); } else { assert(MO.isDef()); - // FIXME: We should not remove any dead flags. However the MIPS RDDSP - // instruction needs it at the moment: http://llvm.org/PR27116. - if (TargetRegisterInfo::isPhysicalRegister(MOReg) && - !MRI->isReserved(MOReg)) - MO.setIsDead(false); DefRegs.push_back(MOReg); } } Index: lib/CodeGen/MachineInstr.cpp =================================================================== --- lib/CodeGen/MachineInstr.cpp +++ lib/CodeGen/MachineInstr.cpp @@ -1970,6 +1970,18 @@ addRegisterDefined(*I, &TRI); } +void MachineInstr::setImplicitRegsDead( + DenseMap &ImplicitRegs) { + for (MachineOperand &MO : implicit_operands()) { + if (MO.isRegMask() || !MO.isReg() || !MO.isDef()) + continue; + unsigned Reg = MO.getReg(); + if (!TargetRegisterInfo::isPhysicalRegister(Reg)) + continue; + ImplicitRegs[Reg] = &MO; + } +} + unsigned MachineInstrExpressionTrait::getHashValue(const MachineInstr* const &MI) { // Build up a buffer of hash code components. @@ -2176,3 +2188,21 @@ return getSpillSlotSize(Accesses, getMF()->getFrameInfo()); return None; } + +void MachineInstr::addRegisterUse(unsigned Reg, + const TargetRegisterInfo *RegInfo) { + if (TargetRegisterInfo::isPhysicalRegister(Reg)) { + MachineOperand *MO = findRegisterUseOperand(Reg, false, RegInfo); + if (MO) + return; + } else { + for (const MachineOperand &MO : operands()) { + if (MO.isReg() && MO.getReg() == Reg && MO.isUse() && + MO.getSubReg() == 0) + return; + } + } + addOperand(MachineOperand::CreateReg(Reg, + false /*IsDef*/, + true /*IsImp*/)); +} Index: lib/CodeGen/SelectionDAG/InstrEmitter.h =================================================================== --- lib/CodeGen/SelectionDAG/InstrEmitter.h +++ lib/CodeGen/SelectionDAG/InstrEmitter.h @@ -35,6 +35,10 @@ MachineBasicBlock *MBB; MachineBasicBlock::iterator InsertPos; + /// Tracks implicit operands that are added by post-isel target hook as they + /// might be incorrectly marked as dead. + DenseMap ImplicitRegs; + /// EmitCopyFromReg - Generate machine code for an CopyFromReg node or an /// implicit physical register output. void EmitCopyFromReg(SDNode *Node, unsigned ResNo, Index: lib/CodeGen/SelectionDAG/InstrEmitter.cpp =================================================================== --- lib/CodeGen/SelectionDAG/InstrEmitter.cpp +++ lib/CodeGen/SelectionDAG/InstrEmitter.cpp @@ -971,6 +971,9 @@ // Run post-isel target hook to adjust this instruction if needed. if (II.hasPostISelHook()) TLI->AdjustInstrPostInstrSelection(*MIB, Node); + + // Cleanup and track any new implicit operands added by post-isel hook. + TLI->AdjustImplicitRegsDead(*MIB, ImplicitRegs, II); } /// EmitSpecialNode - Generate machine code for a target-independent node and @@ -1133,7 +1136,7 @@ // then remove the early-clobber flag. for (unsigned Reg : ECRegs) { if (MIB->readsRegister(Reg, TRI)) { - MachineOperand *MO = + MachineOperand *MO = MIB->findRegisterDefOperand(Reg, false, false, TRI); assert(MO && "No def operand for clobbered register?"); MO->setIsEarlyClobber(false); Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -300,6 +300,10 @@ "it must implement TargetLowering::AdjustInstrPostInstrSelection!"); } +void TargetLowering::AdjustImplicitRegsDead( + MachineInstr &MI, DenseMap &ImplicitRegs, + const MCInstrDesc &II) const {} + //===----------------------------------------------------------------------===// // SelectionDAGISel code //===----------------------------------------------------------------------===// Index: lib/Target/Mips/MicroMipsDSPInstrInfo.td =================================================================== --- lib/Target/Mips/MicroMipsDSPInstrInfo.td +++ lib/Target/Mips/MicroMipsDSPInstrInfo.td @@ -362,6 +362,7 @@ string AsmString = !strconcat("rddsp", "\t$rt, $mask"); list Pattern = [(set GPR32Opnd:$rt, (int_mips_rddsp immZExt7:$mask))]; InstrItinClass Itinerary = NoItinerary; + bit hasPostISelHook = 1; } class REPL_QB_MM_DESC { @@ -386,6 +387,7 @@ list Pattern = [(int_mips_wrdsp GPR32Opnd:$rt, immZExt7:$mask)]; InstrItinClass Itinerary = NoItinerary; bit isMoveReg = 1; + bit hasPostISelHook = 1; } class BPOSGE32C_MMR3_DESC { Index: lib/Target/Mips/MipsDSPInstrInfo.td =================================================================== --- lib/Target/Mips/MipsDSPInstrInfo.td +++ lib/Target/Mips/MipsDSPInstrInfo.td @@ -447,6 +447,7 @@ InstrItinClass Itinerary = itin; string BaseOpcode = instr_asm; bit isMoveReg = 1; + bit hasPostISelHook = 1; } class WRDSP_DESC_BASE { Index: lib/Target/Mips/MipsISelLowering.h =================================================================== --- lib/Target/Mips/MipsISelLowering.h +++ lib/Target/Mips/MipsISelLowering.h @@ -342,6 +342,11 @@ EmitInstrWithCustomInserter(MachineInstr &MI, MachineBasicBlock *MBB) const override; + void + AdjustImplicitRegsDead(MachineInstr &MI, + DenseMap &ImplicitRegs, + const MCInstrDesc &II) const override; + void AdjustInstrPostInstrSelection(MachineInstr &MI, SDNode *Node) const override; Index: lib/Target/Mips/MipsISelLowering.cpp =================================================================== --- lib/Target/Mips/MipsISelLowering.cpp +++ lib/Target/Mips/MipsISelLowering.cpp @@ -2964,11 +2964,54 @@ Ops.push_back(InFlag); } +static void addDSPCtrlRegisterImplicitDefs(MachineInstr &MI, + const TargetRegisterInfo &TRI) { + unsigned Mask = MI.getOperand(1).getImm(); + if (Mask & 1) + MI.addRegisterDefined(Mips::DSPPos, &TRI); + if (Mask & 2) + MI.addRegisterDefined(Mips::DSPSCount, &TRI); + if (Mask & 4) + MI.addRegisterDefined(Mips::DSPCarry, &TRI); + if (Mask & 8) + MI.addRegisterDefined(Mips::DSPOutFlag, &TRI); + if (Mask & 16) + MI.addRegisterDefined(Mips::DSPCCond, &TRI); + if (Mask & 32) + MI.addRegisterDefined(Mips::DSPEFI, &TRI); +} + +static void addDSPCtrlRegisterImplicitUses(MachineInstr &MI, + const TargetRegisterInfo &TRI) { + unsigned Mask = MI.getOperand(1).getImm(); + if (Mask & 1) + MI.addRegisterUse(Mips::DSPPos, &TRI); + if (Mask & 2) + MI.addRegisterUse(Mips::DSPSCount, &TRI); + if (Mask & 4) + MI.addRegisterUse(Mips::DSPCarry, &TRI); + if (Mask & 8) + MI.addRegisterUse(Mips::DSPOutFlag, &TRI); + if (Mask & 16) + MI.addRegisterUse(Mips::DSPCCond, &TRI); + if (Mask & 32) + MI.addRegisterUse(Mips::DSPEFI, &TRI); +} + void MipsTargetLowering::AdjustInstrPostInstrSelection(MachineInstr &MI, SDNode *Node) const { + const TargetRegisterInfo &TRI = *Subtarget.getRegisterInfo(); switch (MI.getOpcode()) { default: return; + case Mips::RDDSP: + case Mips::RDDSP_MM: + addDSPCtrlRegisterImplicitUses(MI, TRI); + break; + case Mips::WRDSP: + case Mips::WRDSP_MM: + addDSPCtrlRegisterImplicitDefs(MI, TRI); + break; case Mips::JALR: case Mips::JALRPseudo: case Mips::JALR64: @@ -3012,6 +3055,27 @@ } } +void MipsTargetLowering::AdjustImplicitRegsDead( + MachineInstr &MI, DenseMap &ImplicitRegs, + const MCInstrDesc &II) const { + // Check current operands against previously added (if any) if they are used + // and remove dead mark. + if (!ImplicitRegs.empty()) + for (MachineOperand &MO : MI.implicit_operands()) + if (MO.isReg()) { + auto Res = ImplicitRegs.find(MO.getReg()); + if (Res != ImplicitRegs.end()) { + if (Res->second->isDead()) + Res->second->setIsDead(false); + ImplicitRegs.erase(Res); + } + } + + // Mark all newly added implicit operands as dead. + if (II.getImplicitDefs() || II.hasOptionalDef()) + MI.setImplicitRegsDead(ImplicitRegs); +} + /// LowerCall - functions arguments are copied from virtual regs to /// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. SDValue Index: lib/Target/Mips/MipsSEISelDAGToDAG.cpp =================================================================== --- lib/Target/Mips/MipsSEISelDAGToDAG.cpp +++ lib/Target/Mips/MipsSEISelDAGToDAG.cpp @@ -48,32 +48,6 @@ SelectionDAGISel::getAnalysisUsage(AU); } -void MipsSEDAGToDAGISel::addDSPCtrlRegOperands(bool IsDef, MachineInstr &MI, - MachineFunction &MF) { - MachineInstrBuilder MIB(MF, &MI); - unsigned Mask = MI.getOperand(1).getImm(); - unsigned Flag = - IsDef ? RegState::ImplicitDefine : RegState::Implicit | RegState::Undef; - - if (Mask & 1) - MIB.addReg(Mips::DSPPos, Flag); - - if (Mask & 2) - MIB.addReg(Mips::DSPSCount, Flag); - - if (Mask & 4) - MIB.addReg(Mips::DSPCarry, Flag); - - if (Mask & 8) - MIB.addReg(Mips::DSPOutFlag, Flag); - - if (Mask & 16) - MIB.addReg(Mips::DSPCCond, Flag); - - if (Mask & 32) - MIB.addReg(Mips::DSPEFI, Flag); -} - unsigned MipsSEDAGToDAGISel::getMSACtrlReg(const SDValue RegIdx) const { uint64_t RegNum = cast(RegIdx)->getZExtValue(); return Mips::MSACtrlRegClass.getRegister(RegNum); @@ -132,12 +106,6 @@ for (auto &MBB: MF) { for (auto &MI: MBB) { switch (MI.getOpcode()) { - case Mips::RDDSP: - addDSPCtrlRegOperands(false, MI, MF); - break; - case Mips::WRDSP: - addDSPCtrlRegOperands(true, MI, MF); - break; case Mips::BuildPairF64_64: case Mips::ExtractElementF64_64: if (!Subtarget->useOddSPReg()) { Index: test/CodeGen/Mips/dsp-implicit-dead.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/dsp-implicit-dead.ll @@ -0,0 +1,34 @@ +; RUN: llc -march=mipsel -mcpu=mips32r2 -mattr=+dsp -verify-machineinstrs \ +; RUN: -stop-before=prologepilog -o - < %s | FileCheck %s + +; Checks that implicit operands added in post isel hook for RDDSP and WRDSP are +; not incorrectly marked dead in previous instructions. + +declare i32 @llvm.mips.rddsp(i32) nounwind readonly +declare void @llvm.mips.cmpu.le.qb(<4 x i8>, <4 x i8>) nounwind + +define i32 @test__builtin_mips_cmpu_le_qb_before_rddsp(i32 %i0, i32 %a0.coerce, i32 %a1.coerce) nounwind { +entry: +; CHECK: CMPU_LE_QB killed renamable $a1, killed renamable $a2, implicit-def $dspccond +; CHECK-NEXT: renamable $v0 = RDDSP 31, implicit $dsppos, implicit $dspscount, implicit $dspcarry, implicit $dspoutflag, implicit killed $dspccond + %0 = bitcast i32 %a0.coerce to <4 x i8> + %1 = bitcast i32 %a1.coerce to <4 x i8> + tail call void @llvm.mips.cmpu.le.qb(<4 x i8> %0, <4 x i8> %1) + %2 = tail call i32 @llvm.mips.rddsp(i32 31) + ret i32 %2 +} + +declare void @llvm.mips.wrdsp(i32, i32) nounwind +declare <4 x i8> @llvm.mips.pick.qb(<4 x i8>, <4 x i8>) nounwind readonly + +define i32 @test__builtin_mips_pick_qb_before_wrdsp(i32 %i0, i32 %a0.coerce, i32 %a1.coerce) nounwind readonly { +entry: +; CHECK: WRDSP killed renamable $a0, 16, implicit-def $dspccond +; CHECK-NEXT: renamable $v0 = PICK_QB killed renamable $a1, killed renamable $a2, implicit killed $dspccond + %0 = bitcast i32 %a0.coerce to <4 x i8> + %1 = bitcast i32 %a1.coerce to <4 x i8> + tail call void @llvm.mips.wrdsp(i32 %i0, i32 16) + %2 = tail call <4 x i8> @llvm.mips.pick.qb(<4 x i8> %0, <4 x i8> %1) + %3 = bitcast <4 x i8> %2 to i32 + ret i32 %3 +}