Index: include/llvm/CodeGen/MachineInstr.h =================================================================== --- include/llvm/CodeGen/MachineInstr.h +++ include/llvm/CodeGen/MachineInstr.h @@ -529,6 +529,12 @@ return hasProperty(MCID::MoveImm, Type); } + /// Return true if this instruction is a register move. + /// (including moving values from subreg to reg) + bool isMoveReg(QueryType Type = IgnoreBundle) const { + return hasProperty(MCID::MoveReg, Type); + } + /// Return true if this instruction is a bitcast instruction. bool isBitcast(QueryType Type = IgnoreBundle) const { return hasProperty(MCID::Bitcast, Type); Index: include/llvm/CodeGen/TargetInstrInfo.h =================================================================== --- include/llvm/CodeGen/TargetInstrInfo.h +++ include/llvm/CodeGen/TargetInstrInfo.h @@ -822,6 +822,12 @@ llvm_unreachable("Target didn't implement TargetInstrInfo::copyPhysReg!"); } + /// If the specific machine instruction is a instruction that moves/copies + /// value from one register to another register return true. + virtual bool isCopyInstr(MachineInstr &MI) const { + return MI.isMoveReg(); + } + /// Store the specified register of the given register class to the specified /// stack frame index. The store instruction is to be added to the given /// machine basic block before the specified machine instruction. If isKill Index: include/llvm/MC/MCInstrDesc.h =================================================================== --- include/llvm/MC/MCInstrDesc.h +++ include/llvm/MC/MCInstrDesc.h @@ -130,6 +130,7 @@ IndirectBranch, Compare, MoveImm, + MoveReg, Bitcast, Select, DelaySlot, @@ -247,6 +248,9 @@ /// \brief Return true if the instruction is an add instruction. bool isAdd() const { return Flags & (1ULL << MCID::Add); } + /// \brief Return true if the instruction is move. + bool isMoveReg() const { return Flags & (1ULL << MCID::MoveReg); } + /// \brief Return true if the instruction is a call. bool isCall() const { return Flags & (1ULL << MCID::Call); } Index: include/llvm/Target/Target.td =================================================================== --- include/llvm/Target/Target.td +++ include/llvm/Target/Target.td @@ -435,6 +435,7 @@ bit isIndirectBranch = 0; // Is this instruction an indirect branch? bit isCompare = 0; // Is this instruction a comparison instruction? bit isMoveImm = 0; // Is this instruction a move immediate instruction? + bit isMoveReg = 0; // Is this instruction a move register instruction? bit isBitcast = 0; // Is this instruction a bitcast instruction? bit isSelect = 0; // Is this instruction a select instruction? bit isBarrier = 0; // Can control flow fall through this instruction? Index: lib/CodeGen/LiveDebugValues.cpp =================================================================== --- lib/CodeGen/LiveDebugValues.cpp +++ lib/CodeGen/LiveDebugValues.cpp @@ -40,6 +40,7 @@ #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/CodeGen/RegisterScavenging.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/Function.h" @@ -81,6 +82,7 @@ const TargetRegisterInfo *TRI; const TargetInstrInfo *TII; const TargetFrameLowering *TFI; + BitVector CalleeSavedRegs; LexicalScopes LS; /// Keeps track of lexical scopes associated with a user value's source @@ -178,11 +180,11 @@ using VarLocMap = UniqueVector; using VarLocSet = SparseBitVector<>; using VarLocInMBB = SmallDenseMap; - struct SpillDebugPair { - MachineInstr *SpillInst; + struct TransferDebugPair { + MachineInstr *TransferInst; MachineInstr *DebugInst; }; - using SpillMap = SmallVector; + using TransferMap = SmallVector; /// This holds the working set of currently open ranges. For fast /// access, this is done both as a set of VarLocIDs, and a map of @@ -234,19 +236,27 @@ bool isSpillInstruction(const MachineInstr &MI, MachineFunction *MF, unsigned &Reg); + bool isCopyInstruction(MachineInstr &MI, unsigned &SrcReg, + unsigned &DefReg); int extractSpillBaseRegAndOffset(const MachineInstr &MI, unsigned &Reg); + void makeTrsfDebugPair(MachineInstr &MI, OpenRangesSet &OpenRanges, + TransferMap &Transfers, VarLocMap &VarLocIDs, + unsigned OldVarID, unsigned NewReg = 0); + void transferDebugValue(const MachineInstr &MI, OpenRangesSet &OpenRanges, VarLocMap &VarLocIDs); void transferSpillInst(MachineInstr &MI, OpenRangesSet &OpenRanges, - VarLocMap &VarLocIDs, SpillMap &Spills); + VarLocMap &VarLocIDs, TransferMap &Transfers); + void transferRegisterCopy(MachineInstr &MI, OpenRangesSet &OpenRanges, + VarLocMap &VarLocIDs, TransferMap &Transfers); void transferRegisterDef(MachineInstr &MI, OpenRangesSet &OpenRanges, const VarLocMap &VarLocIDs); bool transferTerminatorInst(MachineInstr &MI, OpenRangesSet &OpenRanges, VarLocInMBB &OutLocs, const VarLocMap &VarLocIDs); bool transfer(MachineInstr &MI, OpenRangesSet &OpenRanges, - VarLocInMBB &OutLocs, VarLocMap &VarLocIDs, SpillMap &Spills, - bool transferSpills); + VarLocInMBB &OutLocs, VarLocMap &VarLocIDs, + TransferMap &Transfers, bool transferChanges); bool join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs, VarLocInMBB &InLocs, const VarLocMap &VarLocIDs, @@ -369,6 +379,57 @@ } } +/// Create new TransferDebugPair and insert it in @Transfers map. We don't +/// insert it yet to avoid invalidating the iteration in our caller. The +/// VarLoc with @OldVarID should deleted form @OpenRanges and replaced with +/// new VarLoc. If @NewReg is different than default zero value then the +/// new location will be spilled location, otherwise it is variable's new +/// register location created by register copy like instruction. +void LiveDebugValues::makeTrsfDebugPair(MachineInstr &MI, + OpenRangesSet &OpenRanges, + TransferMap &Transfers, + VarLocMap &VarLocIDs, + unsigned OldVarID, unsigned NewReg) { + const MachineInstr *DMI = &VarLocIDs[OldVarID].MI; + MachineFunction *MF = MI.getParent()->getParent(); + MachineInstr *NewDMI; + if (NewReg) { + // Create a DBG_VALUE instruction to describe the Var in its new + // register location. + NewDMI = BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(), + DMI->isIndirectDebugValue(), NewReg, DMI->getDebugVariable(), + DMI->getDebugExpression()); + if (DMI->isIndirectDebugValue()) + NewDMI->getOperand(1).setImm(DMI->getOperand(1).getImm()); + DEBUG(dbgs() << "Creating DBG_VALUE inst for register copy: "; + NewDMI->print(dbgs(), false, false, false, TII)); + } else { + // Create a DBG_VALUE instruction to describe the Var in its spilled + // location. + unsigned SpillBase; + int SpillOffset = extractSpillBaseRegAndOffset(MI, SpillBase); + auto *SpillExpr = DIExpression::prepend( + DMI->getDebugExpression(), DIExpression::NoDeref, SpillOffset); + NewDMI = BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(), true, + SpillBase, DMI->getDebugVariable(), SpillExpr); + DEBUG(dbgs() << "Creating DBG_VALUE inst for spill: "; + NewDMI->print(dbgs(), false, false, false, TII)); + } + + // The newly created DBG_VALUE instruction NewDMI must be inserted after + // MI. Keep track of the pairing. + TransferDebugPair MIP = {&MI, NewDMI}; + Transfers.push_back(MIP); + + // End all previous ranges of Var. + OpenRanges.erase(VarLocIDs[OldVarID].Var); + + // Add the VarLoc to OpenRanges. + VarLoc VL(*NewDMI, LS); + unsigned LocID = VarLocIDs.insert(VL); + OpenRanges.insert(LocID, VL.Var); +} + /// A definition of a register may mark the end of a range. void LiveDebugValues::transferRegisterDef(MachineInstr &MI, OpenRangesSet &OpenRanges, @@ -464,13 +525,13 @@ /// A spilled register may indicate that we have to end the current range of /// a variable and create a new one for the spill location. /// We don't want to insert any instructions in transfer(), so we just create -/// the DBG_VALUE witout inserting it and keep track of it in @Spills. +/// the DBG_VALUE without inserting it and keep track of it in @Transfers. /// It will be inserted into the BB when we're done iterating over the /// instructions. void LiveDebugValues::transferSpillInst(MachineInstr &MI, OpenRangesSet &OpenRanges, VarLocMap &VarLocIDs, - SpillMap &Spills) { + TransferMap &Transfers) { unsigned Reg; MachineFunction *MF = MI.getMF(); if (!isSpillInstruction(MI, MF, Reg)) @@ -481,33 +542,61 @@ if (VarLocIDs[ID].isDescribedByReg() == Reg) { DEBUG(dbgs() << "Spilling Register " << printReg(Reg, TRI) << '(' << VarLocIDs[ID].Var.getVar()->getName() << ")\n"); + makeTrsfDebugPair(MI, OpenRanges, Transfers, VarLocIDs, ID); + return; + } + } +} + +/// Check whether @MI is instruction that copies value from one register +/// to another one. If it is copy instruction return true along with @SrcReg +/// and newly defined location register @DefReg. We are only looking for +/// instruction in which source registers is killed after copy instruction +/// and copies where @DefReg is callee saved register. +bool LiveDebugValues::isCopyInstruction(MachineInstr &MI, unsigned &SrcReg, + unsigned &DefReg) { + MachineFunction *MF = MI.getParent()->getParent(); + const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); + unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); + if (!TII->isCopyInstr(MI)) + return false; - // Create a DBG_VALUE instruction to describe the Var in its spilled - // location, but don't insert it yet to avoid invalidating the - // iterator in our caller. - unsigned SpillBase; - int SpillOffset = extractSpillBaseRegAndOffset(MI, SpillBase); - const MachineInstr *DMI = &VarLocIDs[ID].MI; - auto *SpillExpr = DIExpression::prepend( - DMI->getDebugExpression(), DIExpression::NoDeref, SpillOffset); - MachineInstr *SpDMI = - BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(), true, SpillBase, - DMI->getDebugVariable(), SpillExpr); - DEBUG(dbgs() << "Creating DBG_VALUE inst for spill: "; - SpDMI->print(dbgs(), false, TII)); - - // The newly created DBG_VALUE instruction SpDMI must be inserted after - // MI. Keep track of the pairing. - SpillDebugPair MIP = {&MI, SpDMI}; - Spills.push_back(MIP); - - // End all previous ranges of Var. - OpenRanges.erase(VarLocIDs[ID].Var); - - // Add the VarLoc to OpenRanges. - VarLoc VL(*SpDMI, LS); - unsigned SpillLocID = VarLocIDs.insert(VL); - OpenRanges.insert(SpillLocID, VL.Var); + for (const MachineOperand &MO : MI.operands()) { + if (MO.isReg() && MO.getReg() && TRI->isPhysicalRegister(MO.getReg()) && + !(MI.isCall() && MO.getReg() == SP)) { + if (MO.isDef()) + DefReg = MO.getReg(); + else if (MO.isKill()) + SrcReg = MO.getReg(); + } + } + // We just want to recognize instructions after which we have both killed + // end defined register register. + if (!DefReg || !SrcReg) + return false; + + // We want to recognize instructions where destination register is callee + // saved register. + for (MCRegAliasIterator RAI(DefReg, TRI, true); RAI.isValid(); ++RAI) + if (CalleeSavedRegs.test(*RAI)) + return true; + return false; +} + +/// If @MI is register copy instruction that copies previously tracked value +/// from one register to another we create new DBG_VALEU instruction described +/// with copy destination register. +void LiveDebugValues::transferRegisterCopy(MachineInstr &MI, + OpenRangesSet &OpenRanges, + VarLocMap &VarLocIDs, + TransferMap &Transfers) { + unsigned Reg = 0; + unsigned DefReg = 0; + if(!isCopyInstruction(MI, Reg, DefReg)) + return; + for (unsigned ID : OpenRanges.getVarLocs()) { + if (VarLocIDs[ID].isDescribedByReg() == Reg) { + makeTrsfDebugPair(MI, OpenRanges, Transfers, VarLocIDs, ID, DefReg); return; } } @@ -528,7 +617,8 @@ DEBUG(for (unsigned ID : OpenRanges.getVarLocs()) { // Copy OpenRanges to OutLocs, if not already present. - dbgs() << "Add to OutLocs: "; VarLocIDs[ID].dump(); + dbgs() << "Add to OutLocs: "; + VarLocIDs[ID].MI.print(dbgs(), false, false, false, TII); }); VarLocSet &VLS = OutLocs[CurMBB]; Changed = VLS |= OpenRanges.getVarLocs(); @@ -539,12 +629,14 @@ /// This routine creates OpenRanges and OutLocs. bool LiveDebugValues::transfer(MachineInstr &MI, OpenRangesSet &OpenRanges, VarLocInMBB &OutLocs, VarLocMap &VarLocIDs, - SpillMap &Spills, bool transferSpills) { + TransferMap &Transfers, bool transferChanges) { bool Changed = false; transferDebugValue(MI, OpenRanges, VarLocIDs); transferRegisterDef(MI, OpenRanges, VarLocIDs); - if (transferSpills) - transferSpillInst(MI, OpenRanges, VarLocIDs, Spills); + if (transferChanges) { + transferRegisterCopy(MI, OpenRanges, VarLocIDs, Transfers); + transferSpillInst(MI, OpenRanges, VarLocIDs, Transfers); + } Changed = transferTerminatorInst(MI, OpenRanges, OutLocs, VarLocIDs); return Changed; } @@ -636,7 +728,7 @@ OpenRangesSet OpenRanges; // Ranges that are open until end of bb. VarLocInMBB OutLocs; // Ranges that exist beyond bb. VarLocInMBB InLocs; // Ranges that are incoming after joining. - SpillMap Spills; // DBG_VALUEs associated with spills. + TransferMap Transfers; // DBG_VALUEs associated with spills. DenseMap OrderToBB; DenseMap BBToOrder; @@ -654,8 +746,8 @@ // within the BB in which the spill occurs. for (auto &MBB : MF) for (auto &MI : MBB) - transfer(MI, OpenRanges, OutLocs, VarLocIDs, Spills, - /*transferSpills=*/false); + transfer(MI, OpenRanges, OutLocs, VarLocIDs, Transfers, + /*transferChanges=*/false); DEBUG(printVarLocInMBB(MF, OutLocs, VarLocIDs, "OutLocs after initialization", dbgs())); @@ -691,14 +783,14 @@ // examine spill instructions to see whether they spill registers that // correspond to user variables. for (auto &MI : *MBB) - OLChanged |= transfer(MI, OpenRanges, OutLocs, VarLocIDs, Spills, - /*transferSpills=*/true); + OLChanged |= transfer(MI, OpenRanges, OutLocs, VarLocIDs, Transfers, + /*transferChanges=*/true); // Add any DBG_VALUE instructions necessitated by spills. - for (auto &SP : Spills) - MBB->insertAfter(MachineBasicBlock::iterator(*SP.SpillInst), - SP.DebugInst); - Spills.clear(); + for (auto &TR : Transfers) + MBB->insertAfter(MachineBasicBlock::iterator(*TR.TransferInst), + TR.DebugInst); + Transfers.clear(); DEBUG(printVarLocInMBB(MF, OutLocs, VarLocIDs, "OutLocs after propagating", dbgs())); @@ -738,6 +830,10 @@ TRI = MF.getSubtarget().getRegisterInfo(); TII = MF.getSubtarget().getInstrInfo(); TFI = MF.getSubtarget().getFrameLowering(); + { + RegScavenger RS; + TFI->determineCalleeSaves(MF, CalleeSavedRegs, &RS); + } LS.initialize(MF); bool Changed = ExtendRanges(MF); Index: lib/Target/ARM/ARMInstrInfo.td =================================================================== --- lib/Target/ARM/ARMInstrInfo.td +++ lib/Target/ARM/ARMInstrInfo.td @@ -3351,6 +3351,8 @@ let Inst{25} = 0; let Inst{3-0} = Rm; let Inst{15-12} = Rd; + + let isMoveReg = 1; } // A version for the smaller set of tail call registers. Index: lib/Target/ARM/ARMInstrNEON.td =================================================================== --- lib/Target/ARM/ARMInstrNEON.td +++ lib/Target/ARM/ARMInstrNEON.td @@ -5061,7 +5061,9 @@ def VORRd : N3VDX<0, 0, 0b10, 0b0001, 1, IIC_VBINiD, "vorr", v2i32, v2i32, or, 1>; def VORRq : N3VQX<0, 0, 0b10, 0b0001, 1, IIC_VBINiQ, "vorr", - v4i32, v4i32, or, 1>; + v4i32, v4i32, or, 1> { + let isMoveReg = 1; +} def VORRiv4i16 : N1ModImm<1, 0b000, {1,0,?,1}, 0, 0, 0, 1, (outs DPR:$Vd), (ins nImmSplatI16:$SIMM, DPR:$src), Index: lib/Target/ARM/ARMInstrVFP.td =================================================================== --- lib/Target/ARM/ARMInstrVFP.td +++ lib/Target/ARM/ARMInstrVFP.td @@ -996,6 +996,7 @@ []>; let hasSideEffects = 0 in { +let isMoveReg = 1 in { def VMOVD : ADuI<0b11101, 0b11, 0b0000, 0b01, 0, (outs DPR:$Dd), (ins DPR:$Dm), IIC_fpUNA64, "vmov", ".f64\t$Dd, $Dm", []>; @@ -1003,6 +1004,7 @@ def VMOVS : ASuI<0b11101, 0b11, 0b0000, 0b01, 0, (outs SPR:$Sd), (ins SPR:$Sm), IIC_fpUNA32, "vmov", ".f32\t$Sd, $Sm", []>; +} // isMoveReg let PostEncoderMethod = "", DecoderNamespace = "VFPV8" in { def VMOVH : ASuInp<0b11101, 0b11, 0b0000, 0b01, 0, @@ -1041,6 +1043,8 @@ // Some single precision VFP instructions may be executed on both NEON and VFP // pipelines. let D = VFPNeonDomain; + + let isMoveReg = 1; } // Bitcast i32 -> f32. NEON prefers to use VMOVDRR. @@ -1065,6 +1069,8 @@ // Some single precision VFP instructions may be executed on both NEON and VFP // pipelines. let D = VFPNeonDomain; + + let isMoveReg = 1; } let hasSideEffects = 0 in { Index: lib/Target/Mips/MicroMipsDSPInstrInfo.td =================================================================== --- lib/Target/Mips/MicroMipsDSPInstrInfo.td +++ lib/Target/Mips/MicroMipsDSPInstrInfo.td @@ -525,7 +525,7 @@ def PICK_QB_MM : DspMMRel, PICK_QB_MM_ENC, PICK_QB_DESC; def SHILO_MM : DspMMRel, SHILO_MM_ENC, SHILO_DESC; def SHILOV_MM : DspMMRel, SHILOV_MM_ENC, SHILOV_DESC; -def WRDSP_MM : DspMMRel, WRDSP_MM_ENC, WRDSP_MM_DESC; +def WRDSP_MM : DspMMRel, WRDSP_MM_ENC, WRDSP_MM_DESC { let isMoveReg = 1; } def MODSUB_MM : DspMMRel, MODSUB_MM_ENC, MODSUB_DESC; def MULSAQ_S_W_PH_MM : DspMMRel, MULSAQ_S_W_PH_MM_ENC, MULSAQ_S_W_PH_DESC; def BITREV_MM : DspMMRel, BITREV_MM_ENC, BITREV_MM_DESC; Index: lib/Target/Mips/MicroMipsInstrFPU.td =================================================================== --- lib/Target/Mips/MicroMipsInstrFPU.td +++ lib/Target/Mips/MicroMipsInstrFPU.td @@ -132,7 +132,9 @@ } def FMOV_S_MM : MMRel, ABSS_FT<"mov.s", FGR32Opnd, FGR32Opnd, II_MOV_S>, - ABS_FM_MM<0, 0x1>, ISA_MICROMIPS; + ABS_FM_MM<0, 0x1>, ISA_MICROMIPS { + let isMoveReg = 1; +} def FNEG_S_MM : MMRel, ABSS_FT<"neg.s", FGR32Opnd, FGR32Opnd, II_NEG, fneg>, ABS_FM_MM<0, 0x2d>, ISA_MICROMIPS; Index: lib/Target/Mips/MicroMipsInstrInfo.td =================================================================== --- lib/Target/Mips/MicroMipsInstrInfo.td +++ lib/Target/Mips/MicroMipsInstrInfo.td @@ -630,11 +630,13 @@ def ADDIUR2_MM : AddImmUR2<"addiur2", GPRMM16Opnd>, ADDIUR2_FM_MM16; def ADDIUS5_MM : AddImmUS5<"addius5", GPR32Opnd>, ADDIUS5_FM_MM16; def ADDIUSP_MM : AddImmUSP<"addiusp">, ADDIUSP_FM_MM16; -def MFHI16_MM : MoveFromHILOMM<"mfhi", GPR32Opnd, AC0>, MFHILO_FM_MM16<0x10>; -def MFLO16_MM : MoveFromHILOMM<"mflo", GPR32Opnd, AC0>, MFHILO_FM_MM16<0x12>; -def MOVE16_MM : MoveMM16<"move", GPR32Opnd>, MOVE_FM_MM16<0x03>; -def MOVEP_MM : MovePMM16<"movep", GPRMM16OpndMoveP>, MOVEP_FM_MM16, - ISA_MICROMIPS_NOT_32R6; +let isMoveReg = 1 in { + def MFHI16_MM : MoveFromHILOMM<"mfhi", GPR32Opnd, AC0>, MFHILO_FM_MM16<0x10>; + def MFLO16_MM : MoveFromHILOMM<"mflo", GPR32Opnd, AC0>, MFHILO_FM_MM16<0x12>; + def MOVE16_MM : MoveMM16<"move", GPR32Opnd>, MOVE_FM_MM16<0x03>; + def MOVEP_MM : MovePMM16<"movep", GPRMM16OpndMoveP>, MOVEP_FM_MM16, + ISA_MICROMIPS_NOT_32R6; +} def LI16_MM : LoadImmMM16<"li16", li16_imm, GPRMM16Opnd>, LI_FM_MM16, IsAsCheapAsAMove; def JALR16_MM : JumpLinkRegMM16<"jalr", GPR32Opnd>, JALR_FM_MM16<0x0e>, Index: lib/Target/Mips/Mips16InstrInfo.td =================================================================== --- lib/Target/Mips/Mips16InstrInfo.td +++ lib/Target/Mips/Mips16InstrInfo.td @@ -869,7 +869,9 @@ //Purpose: Move // To move the contents of a GPR to a GPR. // -def MoveR3216: FI8_MOVR3216_ins<"move", IIM16Alu>; +def MoveR3216: FI8_MOVR3216_ins<"move", IIM16Alu> { + let isMoveReg = 1; +} // // Format: MFHI rx MIPS16e @@ -879,6 +881,7 @@ def Mfhi16: FRR16_M_ins<0b10000, "mfhi", IIM16Alu> { let Uses = [HI0]; let hasSideEffects = 0; + let isMoveReg = 1; } // @@ -889,6 +892,7 @@ def Mflo16: FRR16_M_ins<0b10010, "mflo", IIM16Alu> { let Uses = [LO0]; let hasSideEffects = 0; + let isMoveReg = 0; } // Index: lib/Target/Mips/Mips64InstrInfo.td =================================================================== --- lib/Target/Mips/Mips64InstrInfo.td +++ lib/Target/Mips/Mips64InstrInfo.td @@ -290,14 +290,16 @@ II_DDIVU, 0, 1, 1>, ISA_MIPS3_NOT_32R6_64R6; let isCodeGenOnly = 1 in { -def MTHI64 : MoveToLOHI<"mthi", GPR64Opnd, [HI0_64]>, MTLO_FM<0x11>, - ISA_MIPS3_NOT_32R6_64R6; -def MTLO64 : MoveToLOHI<"mtlo", GPR64Opnd, [LO0_64]>, MTLO_FM<0x13>, - ISA_MIPS3_NOT_32R6_64R6; -def MFHI64 : MoveFromLOHI<"mfhi", GPR64Opnd, AC0_64>, MFLO_FM<0x10>, - ISA_MIPS3_NOT_32R6_64R6; -def MFLO64 : MoveFromLOHI<"mflo", GPR64Opnd, AC0_64>, MFLO_FM<0x12>, - ISA_MIPS3_NOT_32R6_64R6; + let isMoveReg = 1 in { + def MTHI64 : MoveToLOHI<"mthi", GPR64Opnd, [HI0_64]>, MTLO_FM<0x11>, + ISA_MIPS3_NOT_32R6_64R6; + def MTLO64 : MoveToLOHI<"mtlo", GPR64Opnd, [LO0_64]>, MTLO_FM<0x13>, + ISA_MIPS3_NOT_32R6_64R6; + def MFHI64 : MoveFromLOHI<"mfhi", GPR64Opnd, AC0_64>, MFLO_FM<0x10>, + ISA_MIPS3_NOT_32R6_64R6; + def MFLO64 : MoveFromLOHI<"mflo", GPR64Opnd, AC0_64>, MFLO_FM<0x12>, + ISA_MIPS3_NOT_32R6_64R6; + } def PseudoMFHI64 : PseudoMFLOHI, ISA_MIPS3_NOT_32R6_64R6; def PseudoMFLO64 : PseudoMFLOHI, @@ -377,10 +379,12 @@ let isCodeGenOnly = 1, rs = 0, shamt = 0 in { def DSLL64_32 : FR<0x00, 0x3c, (outs GPR64:$rd), (ins GPR32:$rt), "dsll\t$rd, $rt, 32", [], II_DSLL>; - def SLL64_32 : FR<0x0, 0x00, (outs GPR64:$rd), (ins GPR32:$rt), - "sll\t$rd, $rt, 0", [], II_SLL>; - def SLL64_64 : FR<0x0, 0x00, (outs GPR64:$rd), (ins GPR64:$rt), - "sll\t$rd, $rt, 0", [], II_SLL>; + let isMoveReg = 1 in { + def SLL64_32 : FR<0x0, 0x00, (outs GPR64:$rd), (ins GPR32:$rt), + "sll\t$rd, $rt, 0", [], II_SLL>; + def SLL64_64 : FR<0x0, 0x00, (outs GPR64:$rd), (ins GPR64:$rt), + "sll\t$rd, $rt, 0", [], II_SLL>; + } } // We need the following pseudo instruction to avoid offset calculation for Index: lib/Target/Mips/MipsDSPInstrInfo.td =================================================================== --- lib/Target/Mips/MipsDSPInstrInfo.td +++ lib/Target/Mips/MipsDSPInstrInfo.td @@ -1163,10 +1163,12 @@ def MAQ_S_W_PHR : DspMMRel, MAQ_S_W_PHR_ENC, MAQ_S_W_PHR_DESC; def MAQ_SA_W_PHL : DspMMRel, MAQ_SA_W_PHL_ENC, MAQ_SA_W_PHL_DESC; def MAQ_SA_W_PHR : DspMMRel, MAQ_SA_W_PHR_ENC, MAQ_SA_W_PHR_DESC; -def MFHI_DSP : DspMMRel, MFHI_ENC, MFHI_DESC; -def MFLO_DSP : DspMMRel, MFLO_ENC, MFLO_DESC; -def MTHI_DSP : DspMMRel, MTHI_ENC, MTHI_DESC; -def MTLO_DSP : DspMMRel, MTLO_ENC, MTLO_DESC; +let isMoveReg = 1 in { + def MFHI_DSP : DspMMRel, MFHI_ENC, MFHI_DESC; + def MFLO_DSP : DspMMRel, MFLO_ENC, MFLO_DESC; + def MTHI_DSP : DspMMRel, MTHI_ENC, MTHI_DESC; + def MTLO_DSP : DspMMRel, MTLO_ENC, MTLO_DESC; +} def DPAU_H_QBL : DspMMRel, DPAU_H_QBL_ENC, DPAU_H_QBL_DESC; def DPAU_H_QBR : DspMMRel, DPAU_H_QBR_ENC, DPAU_H_QBR_DESC; def DPSU_H_QBL : DspMMRel, DPSU_H_QBL_ENC, DPSU_H_QBL_DESC; @@ -1220,9 +1222,11 @@ def SHILO : DspMMRel, SHILO_ENC, SHILO_DESC; def SHILOV : DspMMRel, SHILOV_ENC, SHILOV_DESC; def MTHLIP : DspMMRel, MTHLIP_ENC, MTHLIP_DESC; -def RDDSP : DspMMRel, RDDSP_ENC, RDDSP_DESC; -let AdditionalPredicates = [NotInMicroMips] in { - def WRDSP : WRDSP_ENC, WRDSP_DESC; +let isMoveReg = 1 in { + def RDDSP : DspMMRel, RDDSP_ENC, RDDSP_DESC; + let AdditionalPredicates = [NotInMicroMips] in { + def WRDSP : WRDSP_ENC, WRDSP_DESC; + } } // MIPS DSP Rev 2 Index: lib/Target/Mips/MipsInstrFPU.td =================================================================== --- lib/Target/Mips/MipsInstrFPU.td +++ lib/Target/Mips/MipsInstrFPU.td @@ -475,7 +475,7 @@ // regardless of register aliasing. /// Move Control Registers From/To CPU Registers -let AdditionalPredicates = [NotInMicroMips] in { +let isMoveReg = 1, AdditionalPredicates = [NotInMicroMips] in { def CFC1 : MMRel, MFC1_FT<"cfc1", GPR32Opnd, CCROpnd, II_CFC1>, MFC1_FM<2>; def CTC1 : MMRel, MTC1_FT<"ctc1", CCROpnd, GPR32Opnd, II_CTC1>, MFC1_FM<6>; } @@ -486,7 +486,9 @@ let DecoderNamespace = "MipsFP64"; } def MTC1 : MMRel, MTC1_FT<"mtc1", FGR32Opnd, GPR32Opnd, II_MTC1, - bitconvert>, MFC1_FM<4>; + bitconvert>, MFC1_FM<4> { + let isMoveReg = 1; +} def MTC1_D64 : MTC1_FT<"mtc1", FGR64Opnd, GPR32Opnd, II_MTC1>, MFC1_FM<4>, FGR_64 { let DecoderNamespace = "MipsFP64"; @@ -508,7 +510,7 @@ let DecoderNamespace = "MipsFP64"; } } -let AdditionalPredicates = [NotInMicroMips] in { +let AdditionalPredicates = [NotInMicroMips], isMoveReg = 1 in { def DMTC1 : MTC1_FT<"dmtc1", FGR64Opnd, GPR64Opnd, II_DMTC1, bitconvert>, MFC1_FM<5>, ISA_MIPS3; def DMFC1 : MFC1_FT<"dmfc1", GPR64Opnd, FGR64Opnd, II_DMFC1, Index: lib/Target/Mips/MipsInstrInfo.td =================================================================== --- lib/Target/Mips/MipsInstrInfo.td +++ lib/Target/Mips/MipsInstrInfo.td @@ -2167,16 +2167,19 @@ def UDIV : MMRel, Div<"divu", II_DIVU, GPR32Opnd, [HI0, LO0]>, MULT_FM<0, 0x1b>, ISA_MIPS1_NOT_32R6_64R6; } -def MTHI : MMRel, MoveToLOHI<"mthi", GPR32Opnd, [HI0]>, MTLO_FM<0x11>, - ISA_MIPS1_NOT_32R6_64R6; -def MTLO : MMRel, MoveToLOHI<"mtlo", GPR32Opnd, [LO0]>, MTLO_FM<0x13>, - ISA_MIPS1_NOT_32R6_64R6; +let isMoveReg = 1 in { + def MTHI : MMRel, MoveToLOHI<"mthi", GPR32Opnd, [HI0]>, MTLO_FM<0x11>, + ISA_MIPS1_NOT_32R6_64R6; + def MTLO : MMRel, MoveToLOHI<"mtlo", GPR32Opnd, [LO0]>, MTLO_FM<0x13>, + ISA_MIPS1_NOT_32R6_64R6; +} let EncodingPredicates = [], // FIXME: Lack of HasStdEnc is probably a bug - AdditionalPredicates = [NotInMicroMips] in { -def MFHI : MMRel, MoveFromLOHI<"mfhi", GPR32Opnd, AC0>, MFLO_FM<0x10>, - ISA_MIPS1_NOT_32R6_64R6; -def MFLO : MMRel, MoveFromLOHI<"mflo", GPR32Opnd, AC0>, MFLO_FM<0x12>, - ISA_MIPS1_NOT_32R6_64R6; + AdditionalPredicates = [NotInMicroMips], + isMoveReg = 1 in { + def MFHI : MMRel, MoveFromLOHI<"mfhi", GPR32Opnd, AC0>, MFLO_FM<0x10>, + ISA_MIPS1_NOT_32R6_64R6; + def MFLO : MMRel, MoveFromLOHI<"mflo", GPR32Opnd, AC0>, MFLO_FM<0x12>, + ISA_MIPS1_NOT_32R6_64R6; } /// Sign Ext In Register Instructions. Index: lib/Target/Mips/MipsMSAInstrInfo.td =================================================================== --- lib/Target/Mips/MipsMSAInstrInfo.td +++ lib/Target/Mips/MipsMSAInstrInfo.td @@ -2883,7 +2883,7 @@ def CEQI_W : CEQI_W_ENC, CEQI_W_DESC; def CEQI_D : CEQI_D_ENC, CEQI_D_DESC; -def CFCMSA : CFCMSA_ENC, CFCMSA_DESC; +def CFCMSA : CFCMSA_ENC, CFCMSA_DESC { let isMoveReg = 1; } def CLE_S_B : CLE_S_B_ENC, CLE_S_B_DESC; def CLE_S_H : CLE_S_H_ENC, CLE_S_H_DESC; @@ -2937,7 +2937,7 @@ def COPY_FW_PSEUDO : COPY_FW_PSEUDO_DESC; def COPY_FD_PSEUDO : COPY_FD_PSEUDO_DESC; -def CTCMSA : CTCMSA_ENC, CTCMSA_DESC; +def CTCMSA : CTCMSA_ENC, CTCMSA_DESC { let isMoveReg = 1; } def DIV_S_B : DIV_S_B_ENC, DIV_S_B_DESC; def DIV_S_H : DIV_S_H_ENC, DIV_S_H_DESC; @@ -3289,7 +3289,7 @@ def MOD_U_W : MOD_U_W_ENC, MOD_U_W_DESC; def MOD_U_D : MOD_U_D_ENC, MOD_U_D_DESC; -def MOVE_V : MOVE_V_ENC, MOVE_V_DESC; +def MOVE_V : MOVE_V_ENC, MOVE_V_DESC { let isMoveReg = 1; } def MSUB_Q_H : MSUB_Q_H_ENC, MSUB_Q_H_DESC; def MSUB_Q_W : MSUB_Q_W_ENC, MSUB_Q_W_DESC; Index: lib/Target/Mips/MipsSEInstrInfo.h =================================================================== --- lib/Target/Mips/MipsSEInstrInfo.h +++ lib/Target/Mips/MipsSEInstrInfo.h @@ -47,6 +47,8 @@ const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, bool KillSrc) const override; + bool isCopyInstr(MachineInstr &MI) const override; + void storeRegToStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, unsigned SrcReg, bool isKill, int FrameIndex, Index: lib/Target/Mips/MipsSEInstrInfo.cpp =================================================================== --- lib/Target/Mips/MipsSEInstrInfo.cpp +++ lib/Target/Mips/MipsSEInstrInfo.cpp @@ -179,6 +179,22 @@ MIB.addReg(ZeroReg); } +bool MipsSEInstrInfo::isCopyInstr(MachineInstr &MI) const { + if(TargetInstrInfo::isCopyInstr(MI)) + return true; + switch (MI.getOpcode()) { + case Mips::OR_MM: + case Mips::OR: + if (MI.getOperand(2).getReg() == Mips::ZERO) + return true; + case Mips::OR64: + if (MI.getOperand(2).getReg() == Mips::ZERO_64) + return true; + default: + return false; + } +} + void MipsSEInstrInfo:: storeRegToStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, unsigned SrcReg, bool isKill, int FI, Index: lib/Target/X86/X86InstrInfo.td =================================================================== --- lib/Target/X86/X86InstrInfo.td +++ lib/Target/X86/X86InstrInfo.td @@ -1443,7 +1443,7 @@ // Move Instructions. // let SchedRW = [WriteMove] in { -let hasSideEffects = 0 in { +let hasSideEffects = 0, isMoveReg = 1 in { def MOV8rr : I<0x88, MRMDestReg, (outs GR8 :$dst), (ins GR8 :$src), "mov{b}\t{$src, $dst|$dst, $src}", [], IIC_MOV>; def MOV16rr : I<0x89, MRMDestReg, (outs GR16:$dst), (ins GR16:$src), @@ -1661,7 +1661,7 @@ // that they can be used for copying and storing h registers, which can't be // encoded when a REX prefix is present. let isCodeGenOnly = 1 in { -let hasSideEffects = 0 in +let hasSideEffects = 0, isMoveReg = 1 in def MOV8rr_NOREX : I<0x88, MRMDestReg, (outs GR8_NOREX:$dst), (ins GR8_NOREX:$src), "mov{b}\t{$src, $dst|$dst, $src}", [], IIC_MOV>, Index: lib/Target/X86/X86InstrMMX.td =================================================================== --- lib/Target/X86/X86InstrMMX.td +++ lib/Target/X86/X86InstrMMX.td @@ -286,10 +286,11 @@ "movq\t{$src, $dst|$dst, $src}", [(set GR64:$dst, (bitconvert VR64:$src))], IIC_MMX_MOV_REG_MM>; -let hasSideEffects = 0 in +let hasSideEffects = 0, isMoveReg = 1 in { def MMX_MOVQ64rr : MMXI<0x6F, MRMSrcReg, (outs VR64:$dst), (ins VR64:$src), "movq\t{$src, $dst|$dst, $src}", [], IIC_MMX_MOVQ_RR>; +} let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0 in { def MMX_MOVQ64rr_REV : MMXI<0x7F, MRMDestReg, (outs VR64:$dst), (ins VR64:$src), "movq\t{$src, $dst|$dst, $src}", [], Index: test/DebugInfo/MIR/Mips/live-debug-value-reg-copy.mir =================================================================== --- /dev/null +++ test/DebugInfo/MIR/Mips/live-debug-value-reg-copy.mir @@ -0,0 +1,206 @@ +# RUN: llc -run-pass=livedebugvalues %s -o - | FileCheck %s +# +# This testcase tests tracking variables value transferning from one register to another. +# Some of instructions were added to +# +# CHECK: ![[ARG1:.*]] = !DILocalVariable(name: "arg1" +# CHECK: DBG_VALUE debug-use $at, debug-use $noreg, ![[ARG1]], !DIExpression(), debug-location +# CHECK-NEXT: renamable $s1_64 = SLL64_32 killed renamable $at, debug-location +# CHECK-NEXT: DBG_VALUE debug-use $s1_64, debug-use $noreg, ![[ARG1]], !DIExpression(), debug-location + +--- | + ; ModuleID = 'live-debug-value-reg-copy.ll' + source_filename = "live-debug-value-reg-copy.c" + target datalayout = "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128" + target triple = "mips64-octeon-linux" + + define i32 @foo(i32 signext %arg1) local_unnamed_addr !dbg !8 { + entry: + call void @llvm.dbg.value(metadata i32 %arg1, metadata !13, metadata !DIExpression()), !dbg !16 + call void @llvm.dbg.value(metadata i32 0, metadata !14, metadata !DIExpression()), !dbg !17 + call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression()), !dbg !18 + %cmp = icmp sgt i32 %arg1, 10, !dbg !19 + br i1 %cmp, label %if.then, label %if.else, !dbg !21 + + if.then: ; preds = %entry + %call = tail call i32 @externFunc(i32 signext %arg1), !dbg !22 + call void @llvm.dbg.value(metadata i32 %call, metadata !15, metadata !DIExpression()), !dbg !18 + call void @llvm.dbg.value(metadata i32 10, metadata !14, metadata !DIExpression()), !dbg !17 + br label %if.end, !dbg !24 + + if.else: ; preds = %entry + %add2 = add nsw i32 %arg1, 10, !dbg !25 + call void @llvm.dbg.value(metadata i32 %add2, metadata !13, metadata !DIExpression()), !dbg !16 + %call3 = tail call i32 @externFunc2(i32 signext %add2), !dbg !27 + call void @llvm.dbg.value(metadata i32 %call3, metadata !14, metadata !DIExpression()), !dbg !17 + call void @llvm.dbg.value(metadata i32 %call3, metadata !15, metadata !DIExpression()), !dbg !18 + %call5 = tail call i32 @externFunc(i32 signext %add2), !dbg !28 + %add6 = add nsw i32 %call5, %call3, !dbg !29 + call void @llvm.dbg.value(metadata i32 %add6, metadata !15, metadata !DIExpression()), !dbg !18 + br label %if.end + + if.end: ; preds = %if.else, %if.then + %local.0 = phi i32 [ 10, %if.then ], [ %call3, %if.else ] + %result.0 = phi i32 [ %call, %if.then ], [ %add6, %if.else ] + call void @llvm.dbg.value(metadata i32 %local.0, metadata !14, metadata !DIExpression()), !dbg !17 + call void @llvm.dbg.value(metadata i32 %result.0, metadata !15, metadata !DIExpression()), !dbg !18 + %add7 = add nsw i32 %result.0, %local.0, !dbg !30 + call void @llvm.dbg.value(metadata i32 %add7, metadata !15, metadata !DIExpression()), !dbg !18 + ret i32 %add7, !dbg !31 + } + + declare i32 @externFunc(i32 signext) local_unnamed_addr + + declare i32 @externFunc2(i32 signext) local_unnamed_addr + + ; Function Attrs: nounwind readnone speculatable + declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) #1 + + attributes #0 = { nounwind readnone speculatable } + attributes #1 = { nounwind } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3, !4, !5, !6} + !llvm.ident = !{!7} + + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 7.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "live-debug-value-reg-copy.c", directory: "/") + !2 = !{} + !3 = !{i32 2, !"Dwarf Version", i32 4} + !4 = !{i32 2, !"Debug Info Version", i32 3} + !5 = !{i32 1, !"wchar_size", i32 4} + !6 = !{i32 7, !"PIC Level", i32 2} + !7 = !{!"clang version 7.0.0 "} + !8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 4, type: !9, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !12) + !9 = !DISubroutineType(types: !10) + !10 = !{!11, !11} + !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !12 = !{!13, !14, !15} + !13 = !DILocalVariable(name: "arg1", arg: 1, scope: !8, file: !1, line: 4, type: !11) + !14 = !DILocalVariable(name: "local", scope: !8, file: !1, line: 5, type: !11) + !15 = !DILocalVariable(name: "result", scope: !8, file: !1, line: 6, type: !11) + !16 = !DILocation(line: 4, column: 13, scope: !8) + !17 = !DILocation(line: 5, column: 6, scope: !8) + !18 = !DILocation(line: 6, column: 13, scope: !8) + !19 = !DILocation(line: 7, column: 18, scope: !20) + !20 = distinct !DILexicalBlock(scope: !8, file: !1, line: 7, column: 13) + !21 = !DILocation(line: 7, column: 13, scope: !8) + !22 = !DILocation(line: 8, column: 13, scope: !23) + !23 = distinct !DILexicalBlock(scope: !20, file: !1, line: 7, column: 23) + !24 = !DILocation(line: 10, column: 9, scope: !23) + !25 = !DILocation(line: 12, column: 7, scope: !26) + !26 = distinct !DILexicalBlock(scope: !20, file: !1, line: 11, column: 14) + !27 = !DILocation(line: 13, column: 11, scope: !26) + !28 = !DILocation(line: 15, column: 13, scope: !26) + !29 = !DILocation(line: 15, column: 10, scope: !26) + !30 = !DILocation(line: 17, column: 9, scope: !8) + !31 = !DILocation(line: 18, column: 2, scope: !8) + +... +--- +name: foo +alignment: 3 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: false +registers: +liveins: + - { reg: '$a0_64', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 32 + offsetAdjustment: 0 + maxAlignment: 8 + adjustsStack: true + hasCalls: true + stackProtector: '' + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + savePoint: '' + restorePoint: '' +fixedStack: +stack: + - { id: 0, name: '', type: spill-slot, offset: -8, size: 8, alignment: 8, + stack-id: 0, callee-saved-register: '$ra_64', callee-saved-restored: true, + di-variable: '', di-expression: '', di-location: '' } + - { id: 1, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8, + stack-id: 0, callee-saved-register: '$s1_64', callee-saved-restored: true, + di-variable: '', di-expression: '', di-location: '' } + - { id: 2, name: '', type: spill-slot, offset: -24, size: 8, alignment: 8, + stack-id: 0, callee-saved-register: '$s0_64', callee-saved-restored: true, + di-variable: '', di-expression: '', di-location: '' } +constants: +body: | + bb.0.entry: + successors: %bb.1(0x40000000), %bb.2(0x40000000) + + $sp_64 = DADDiu $sp_64, -32 + CFI_INSTRUCTION def_cfa_offset 32 + SD killed $ra_64, $sp_64, 24 :: (store 8 into %stack.0) + SD killed $s1_64, $sp_64, 16 :: (store 8 into %stack.1) + SD killed $s0_64, $sp_64, 8 :: (store 8 into %stack.2) + CFI_INSTRUCTION offset $ra_64, -8 + CFI_INSTRUCTION offset $s1_64, -16 + CFI_INSTRUCTION offset $s0_64, -24 + DBG_VALUE debug-use $a0_64, debug-use $noreg, !13, !DIExpression(), debug-location !16 + DBG_VALUE debug-use $a0, debug-use $noreg, !13, !DIExpression(), debug-location !16 + DBG_VALUE 0, debug-use $noreg, !14, !DIExpression(), debug-location !17 + DBG_VALUE 0, debug-use $noreg, !15, !DIExpression(), debug-location !18 + renamable $at = SLTi renamable $a0, 11, debug-location !19 + BNE killed renamable $at, $zero, %bb.2, implicit-def $at, debug-location !21 { + NOP debug-location !21 + } + + bb.1.if.then: + successors: %bb.3(0x80000000) + + JAL @externFunc, csr_n64, implicit-def dead $ra, implicit $a0_64, implicit-def $sp, implicit-def $v0, debug-location !22 { + renamable $a0_64 = SLL64_32 renamable $a0, implicit killed $a0_64, debug-location !22 + } + DBG_VALUE debug-use $v0, debug-use $noreg, !15, !DIExpression(), debug-location !18 + DBG_VALUE 10, debug-use $noreg, !14, !DIExpression(), debug-location !17 + J %bb.3, implicit-def dead $at, debug-location !24 { + renamable $s0 = ADDiu $zero, 10 + } + + bb.2.if.else: + successors: %bb.3(0x80000000) + + renamable $at = ADDiu renamable $a0, 10, implicit killed $a0_64, debug-location !25 + DBG_VALUE debug-use $at, debug-use $noreg, !13, !DIExpression(), debug-location !16 + renamable $s1_64 = SLL64_32 killed renamable $at, debug-location !27 + JAL @externFunc2, csr_n64, implicit-def dead $ra, implicit $a0_64, implicit-def $sp, implicit-def $v0, debug-location !27 { + $a0_64 = OR64 $s1_64, $zero_64, debug-location !27 + } + $s0 = OR $v0, $zero, debug-location !27 + DBG_VALUE debug-use $s0, debug-use $noreg, !15, !DIExpression(), debug-location !18 + DBG_VALUE debug-use $s0, debug-use $noreg, !14, !DIExpression(), debug-location !17 + JAL @externFunc, csr_n64, implicit-def dead $ra, implicit $a0_64, implicit-def $sp, implicit-def $v0, debug-location !28 { + $a0_64 = OR64 killed $s1_64, $zero_64, debug-location !28 + } + renamable $v0 = ADDu killed renamable $v0, renamable $s0, debug-location !29 + DBG_VALUE debug-use $v0, debug-use $noreg, !15, !DIExpression(), debug-location !18 + + bb.3.if.end: + DBG_VALUE debug-use $v0, debug-use $noreg, !15, !DIExpression(), debug-location !18 + renamable $v0 = ADDu killed renamable $v0, killed renamable $s0, debug-location !30 + DBG_VALUE debug-use $v0, debug-use $noreg, !15, !DIExpression(), debug-location !18 + DBG_VALUE debug-use $s0, debug-use $noreg, !14, !DIExpression(), debug-location !17 + $s0_64 = LD $sp_64, 8, debug-location !31 :: (load 8 from %stack.2) + $s1_64 = LD $sp_64, 16, debug-location !31 :: (load 8 from %stack.1) + $ra_64 = LD $sp_64, 24, debug-location !31 :: (load 8 from %stack.0) + PseudoReturn64 undef $ra_64, implicit $v0, debug-location !31 { + $sp_64 = DADDiu $sp_64, 32 + } + +... Index: utils/TableGen/CodeGenInstruction.h =================================================================== --- utils/TableGen/CodeGenInstruction.h +++ utils/TableGen/CodeGenInstruction.h @@ -226,6 +226,7 @@ bool isIndirectBranch : 1; bool isCompare : 1; bool isMoveImm : 1; + bool isMoveReg : 1; bool isBitcast : 1; bool isSelect : 1; bool isBarrier : 1; Index: utils/TableGen/CodeGenInstruction.cpp =================================================================== --- utils/TableGen/CodeGenInstruction.cpp +++ utils/TableGen/CodeGenInstruction.cpp @@ -306,6 +306,7 @@ isIndirectBranch = R->getValueAsBit("isIndirectBranch"); isCompare = R->getValueAsBit("isCompare"); isMoveImm = R->getValueAsBit("isMoveImm"); + isMoveReg = R->getValueAsBit("isMoveReg"); isBitcast = R->getValueAsBit("isBitcast"); isSelect = R->getValueAsBit("isSelect"); isBarrier = R->getValueAsBit("isBarrier"); Index: utils/TableGen/InstrInfoEmitter.cpp =================================================================== --- utils/TableGen/InstrInfoEmitter.cpp +++ utils/TableGen/InstrInfoEmitter.cpp @@ -489,6 +489,7 @@ if (Inst.isIndirectBranch) OS << "|(1ULL<