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 a register to register 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,26 @@ 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 makeTransferDebugPair(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 +378,58 @@ } } +/// 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::makeTransferDebugPair(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"); + makeTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, ID); + return; + } + } +} + +/// Check whether @MI is instruction that copies value from one register +/// to another one. If it is a copy instruction return true along with @SrcReg +/// and newly defined location register @DefReg. We are only looking for an +/// 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 killed and + // defined registers. + 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 a register copy instruction that copies a 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) { + makeTransferDebugPair(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 @@ -3340,7 +3340,7 @@ // Move Instructions. // -let hasSideEffects = 0 in +let hasSideEffects = 0, isMoveReg = 1 in def MOVr : AsI1<0b1101, (outs GPR:$Rd), (ins GPR:$Rm), DPFrm, IIC_iMOVr, "mov", "\t$Rd, $Rm", []>, UnaryDP, Sched<[WriteALU]> { bits<4> Rd; 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/ARMInstrThumb.td =================================================================== --- lib/Target/ARM/ARMInstrThumb.td +++ lib/Target/ARM/ARMInstrThumb.td @@ -1155,6 +1155,7 @@ // A7-73: MOV(2) - mov setting flag. let hasSideEffects = 0 in { +let isMoveReg = 1 in def tMOVr : Thumb1pI<(outs GPR:$Rd), (ins GPR:$Rm), AddrModeNone, 2, IIC_iMOVr, "mov", "\t$Rd, $Rm", "", []>, 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, @@ -1021,6 +1023,7 @@ // FP <-> GPR Copies. Int <-> FP Conversions. // +let isMoveReg = 1 in { def VMOVRS : AVConv2I<0b11100001, 0b1010, (outs GPR:$Rt), (ins SPR:$Sn), IIC_fpMOVSI, "vmov", "\t$Rt, $Sn", @@ -1066,6 +1069,7 @@ // pipelines. let D = VFPNeonDomain; } +} // isMoveReg let hasSideEffects = 0 in { def VMOVRRD : AVConv3I<0b11000101, 0b1011, Index: lib/Target/Mips/MicroMipsDSPInstrInfo.td =================================================================== --- lib/Target/Mips/MicroMipsDSPInstrInfo.td +++ lib/Target/Mips/MicroMipsDSPInstrInfo.td @@ -386,6 +386,7 @@ string AsmString = !strconcat("wrdsp", "\t$rt, $mask"); list Pattern = [(int_mips_wrdsp GPR32Opnd:$rt, immZExt7:$mask)]; InstrItinClass Itinerary = NoItinerary; + bit isMoveReg = 1; } class BPOSGE32C_MMR3_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 @@ -231,6 +231,7 @@ !strconcat(opstr, "\t$dst_regs, $rs, $rt"), [], NoItinerary, FrmR> { let isReMaterializable = 1; + let isMoveReg = 1; } /// A register pair used by load/store pair instructions. @@ -408,12 +409,14 @@ [], II_MFHI_MFLO, FrmR> { let Uses = [UseReg]; let hasSideEffects = 0; + let isMoveReg = 1; } class MoveMM16 : MicroMipsInst16<(outs RO:$rd), (ins RO:$rs), !strconcat(opstr, "\t$rd, $rs"), [], II_MOVE, FrmR> { let isReMaterializable = 1; + let isMoveReg = 1; } class LoadImmMM16 : 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 @@ -377,10 +377,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 @@ -447,6 +447,7 @@ list Pattern = [(set GPR32Opnd:$rd, (OpNode immZExt10:$mask))]; InstrItinClass Itinerary = itin; string BaseOpcode = instr_asm; + bit isMoveReg = 1; } class WRDSP_DESC_BASE Pattern = [(OpNode GPR32Opnd:$rs, immZExt10:$mask)]; InstrItinClass Itinerary = itin; string BaseOpcode = instr_asm; + bit isMoveReg = 1; } class DPA_W_PH_DESC_BASE { @@ -500,6 +502,7 @@ list Pattern = [(set GPR32Opnd:$rd, (OpNode RO:$ac))]; InstrItinClass Itinerary = itin; string BaseOpcode = instr_asm; + bit isMoveReg = 1; } class MTHI_DESC_BASE { @@ -508,6 +511,7 @@ string AsmString = !strconcat(instr_asm, "\t$rs, $ac"); InstrItinClass Itinerary = itin; string BaseOpcode = instr_asm; + bit isMoveReg = 1; } class BPOSGE32_PSEUDO_DESC_BASE : Index: lib/Target/Mips/MipsInstrFPU.td =================================================================== --- lib/Target/Mips/MipsInstrFPU.td +++ lib/Target/Mips/MipsInstrFPU.td @@ -149,12 +149,16 @@ class MFC1_FT : InstSE<(outs DstRC:$rt), (ins SrcRC:$fs), !strconcat(opstr, "\t$rt, $fs"), - [(set DstRC:$rt, (OpNode SrcRC:$fs))], Itin, FrmFR, opstr>, HARDFLOAT; + [(set DstRC:$rt, (OpNode SrcRC:$fs))], Itin, FrmFR, opstr>, HARDFLOAT { + let isMoveReg = 1; +} class MTC1_FT : InstSE<(outs DstRC:$fs), (ins SrcRC:$rt), !strconcat(opstr, "\t$rt, $fs"), - [(set DstRC:$fs, (OpNode SrcRC:$rt))], Itin, FrmFR, opstr>, HARDFLOAT; + [(set DstRC:$fs, (OpNode SrcRC:$rt))], Itin, FrmFR, opstr>, HARDFLOAT { + let isMoveReg = 1; +} class MTC1_64_FT : @@ -513,14 +517,16 @@ bitconvert>, MFC1_FM<5>, ISA_MIPS3; def DMFC1 : MFC1_FT<"dmfc1", GPR64Opnd, FGR64Opnd, II_DMFC1, bitconvert>, MFC1_FM<1>, ISA_MIPS3; - def FMOV_S : MMRel, ABSS_FT<"mov.s", FGR32Opnd, FGR32Opnd, II_MOV_S>, - ABSS_FM<0x6, 16>; - def FMOV_D32 : MMRel, ABSS_FT<"mov.d", AFGR64Opnd, AFGR64Opnd, II_MOV_D>, - ABSS_FM<0x6, 17>, FGR_32; - def FMOV_D64 : ABSS_FT<"mov.d", FGR64Opnd, FGR64Opnd, II_MOV_D>, - ABSS_FM<0x6, 17>, FGR_64 { - let DecoderNamespace = "MipsFP64"; - } + let isMoveReg = 1 in { + def FMOV_S : MMRel, ABSS_FT<"mov.s", FGR32Opnd, FGR32Opnd, II_MOV_S>, + ABSS_FM<0x6, 16>; + def FMOV_D32 : MMRel, ABSS_FT<"mov.d", AFGR64Opnd, AFGR64Opnd, II_MOV_D>, + ABSS_FM<0x6, 17>, FGR_32; + def FMOV_D64 : ABSS_FT<"mov.d", FGR64Opnd, FGR64Opnd, II_MOV_D>, + ABSS_FM<0x6, 17>, FGR_64 { + let DecoderNamespace = "MipsFP64"; + } + } // isMoveReg } /// Floating Point Memory Instructions Index: lib/Target/Mips/MipsInstrInfo.td =================================================================== --- lib/Target/Mips/MipsInstrInfo.td +++ lib/Target/Mips/MipsInstrInfo.td @@ -1667,6 +1667,7 @@ FrmR, opstr> { let Uses = [UseReg]; let hasSideEffects = 0; + let isMoveReg = 1; } class PseudoMTLOHI @@ -1679,6 +1680,7 @@ FrmR, opstr> { let Defs = DefRegs; let hasSideEffects = 0; + let isMoveReg = 1; } class EffectiveAddress : Index: lib/Target/Mips/MipsMSAInstrInfo.td =================================================================== --- lib/Target/Mips/MipsMSAInstrInfo.td +++ lib/Target/Mips/MipsMSAInstrInfo.td @@ -1780,6 +1780,7 @@ string AsmString = "cfcmsa\t$rd, $cs"; InstrItinClass Itinerary = NoItinerary; bit hasSideEffects = 1; + bit isMoveReg = 1; } class CLE_S_B_DESC : MSA_3R_DESC_BASE<"cle_s.b", vsetle_v16i8, MSA128BOpnd>; @@ -1874,6 +1875,7 @@ string AsmString = "ctcmsa\t$cd, $rs"; InstrItinClass Itinerary = NoItinerary; bit hasSideEffects = 1; + bit isMoveReg = 1; } class DIV_S_B_DESC : MSA_3R_DESC_BASE<"div_s.b", sdiv, MSA128BOpnd>; @@ -2419,6 +2421,7 @@ string AsmString = "move.v\t$wd, $ws"; list Pattern = []; InstrItinClass Itinerary = NoItinerary; + bit isMoveReg = 1; } class MSUB_Q_H_DESC : MSA_3RF_4RF_DESC_BASE<"msub_q.h", int_mips_msub_q_h, 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,23 @@ MIB.addReg(ZeroReg); } +/// We check for the common case of 'or', as it's MIPS' preferred instruction +/// for GPRs but we have to check the operands to ensure that is the case. +/// Other move instructions for MIPS are directly identifiable. +bool MipsSEInstrInfo::isCopyInstr(MachineInstr &MI) const { + 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 TargetInstrInfo::isCopyInstr(MI); + } +} + void MipsSEInstrInfo:: storeRegToStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, unsigned SrcReg, bool isKill, int FI, Index: lib/Target/X86/X86InstrAVX512.td =================================================================== --- lib/Target/X86/X86InstrAVX512.td +++ lib/Target/X86/X86InstrAVX512.td @@ -2729,7 +2729,7 @@ multiclass avx512_mask_mov opc_kk, bits<8> opc_km, bits<8> opc_mk, string OpcodeStr, RegisterClass KRC, ValueType vvt, X86MemOperand x86memop> { - let hasSideEffects = 0, SchedRW = [WriteMove] in + let isMoveReg = 1, hasSideEffects = 0, SchedRW = [WriteMove] in def kk : I, Sched<[WriteMove]>; @@ -2757,6 +2757,7 @@ } let Predicates = [HasDQI] in + let isMoveReg = 0 in defm KMOVB : avx512_mask_mov<0x90, 0x90, 0x91, "kmovb", VK8, v8i1, i8mem>, avx512_mask_mov_gpr<0x92, 0x93, "kmovb", VK8, GR32>, VEX, PD; @@ -2767,6 +2768,7 @@ VEX, PS; let Predicates = [HasBWI] in { + let isMoveReg = 0 in defm KMOVD : avx512_mask_mov<0x90, 0x90, 0x91, "kmovd", VK32, v32i1,i32mem>, VEX, PD, VEX_W; defm KMOVD : avx512_mask_mov_gpr<0x92, 0x93, "kmovd", VK32, GR32>, @@ -3320,7 +3322,6 @@ Predicate prd, bit NoRMPattern = 0, SDPatternOperator SelectOprr = vselect> { - let Predicates = [prd] in defm Z : avx512_load, EVEX_V512; 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: lib/Target/X86/X86InstrSSE.td =================================================================== --- lib/Target/X86/X86InstrSSE.td +++ lib/Target/X86/X86InstrSSE.td @@ -740,6 +740,7 @@ // For disassembler let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0, SchedRW = [WriteFShuffle] in { + let isMoveReg = 1 in def VMOVAPSrr_REV : VPSI<0x29, MRMDestReg, (outs VR128:$dst), (ins VR128:$src), "movaps\t{$src, $dst|$dst, $src}", [], @@ -760,6 +761,7 @@ "movupd\t{$src, $dst|$dst, $src}", [], IIC_SSE_MOVU_P_RR>, VEX, VEX_WIG, FoldGenData<"VMOVUPDrr">; + let isMoveReg = 1 in def VMOVAPSYrr_REV : VPSI<0x29, MRMDestReg, (outs VR256:$dst), (ins VR256:$src), "movaps\t{$src, $dst|$dst, $src}", [], @@ -823,6 +825,7 @@ // For disassembler let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0, SchedRW = [WriteFShuffle] in { + let isMoveReg = 1 in def MOVAPSrr_REV : PSI<0x29, MRMDestReg, (outs VR128:$dst), (ins VR128:$src), "movaps\t{$src, $dst|$dst, $src}", [], IIC_SSE_MOVA_P_RR>, FoldGenData<"MOVAPSrr">; Index: test/DebugInfo/MIR/ARM/live-debug-values-reg-copy.mir =================================================================== --- /dev/null +++ test/DebugInfo/MIR/ARM/live-debug-values-reg-copy.mir @@ -0,0 +1,173 @@ +# RUN: llc -run-pass=livedebugvalues %s -o - | FileCheck %s +# +# This test tests tracking variables value transferring from one register to another. +# This example is altered additionally in order to test transferring from one float register +# to another. The altered instructions are labeled bellow. +# +# CHECK: ![[ARG1:.*]] = !DILocalVariable(name: "arg1" +# CHECK: DBG_VALUE debug-use $r4, debug-use $noreg, ![[ARG1]], !DIExpression(), debug-location +# CHECK: $r5 = MOVr killed $r4, 14, $noreg, $noreg, debug-location +# CHECK-NEXT: DBG_VALUE debug-use $r5, debug-use $noreg, ![[ARG1]], !DIExpression(), debug-location +--- | + ; ModuleID = 'live-debug-values-reg-copy.ll' + source_filename = "live-debug-values-reg-copy.c" + target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" + target triple = "armv4t--" + + define dso_local arm_aapcscc i32 @foo(i32 %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.end, label %if.else, !dbg !21 + + if.else: ; preds = %entry + %add5 = add nsw i32 %arg1, 10, !dbg !22 + call void @llvm.dbg.value(metadata i32 %add5, metadata !13, metadata !DIExpression()), !dbg !16 + %call6 = tail call arm_aapcscc i32 @externFunc2(i32 %add5), !dbg !24 + call void @llvm.dbg.value(metadata i32 %call6, metadata !14, metadata !DIExpression()), !dbg !17 + call void @llvm.dbg.value(metadata i32 %call6, metadata !15, metadata !DIExpression()), !dbg !18 + %call8 = tail call arm_aapcscc i32 @externFunc(i32 %add5), !dbg !25 + ret i32 %call6, !dbg !26 + + if.end: ; preds = %entry + %call = tail call arm_aapcscc i32 @externFunc(i32 %arg1), !dbg !27 + call void @llvm.dbg.value(metadata i32 %call, metadata !15, metadata !DIExpression()), !dbg !18 + call void @llvm.dbg.value(metadata i32 1, metadata !14, metadata !DIExpression()), !dbg !17 + call void @llvm.dbg.value(metadata i32 1, metadata !14, metadata !DIExpression()), !dbg !17 + ret i32 1, !dbg !26 + } + + declare dso_local arm_aapcscc i32 @externFunc(i32) local_unnamed_addr + + declare dso_local arm_aapcscc i32 @externFunc2(i32) 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-values-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 1, !"min_enum_size", i32 4} + !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: 6, scope: !8) + !19 = !DILocation(line: 7, column: 11, scope: !20) + !20 = distinct !DILexicalBlock(scope: !8, file: !1, line: 7, column: 6) + !21 = !DILocation(line: 7, column: 6, scope: !8) + !22 = !DILocation(line: 12, column: 8, scope: !23) + !23 = distinct !DILexicalBlock(scope: !20, file: !1, line: 11, column: 7) + !24 = !DILocation(line: 13, column: 11, scope: !23) + !25 = !DILocation(line: 15, column: 13, scope: !23) + !26 = !DILocation(line: 18, column: 2, scope: !8) + !27 = !DILocation(line: 8, column: 13, scope: !28) + !28 = distinct !DILexicalBlock(scope: !20, file: !1, line: 7, column: 22) + +... +--- +name: foo +alignment: 2 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: false +registers: +liveins: + - { reg: '$r0', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 16 + offsetAdjustment: 0 + maxAlignment: 4 + adjustsStack: true + hasCalls: true + stackProtector: '' + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + savePoint: '' + restorePoint: '' +fixedStack: +stack: + - { id: 0, name: '', type: spill-slot, offset: -4, size: 4, alignment: 4, + stack-id: 0, callee-saved-register: '$lr', callee-saved-restored: true, + di-variable: '', di-expression: '', di-location: '' } + - { id: 1, name: '', type: spill-slot, offset: -8, size: 4, alignment: 4, + stack-id: 0, callee-saved-register: '$r11', callee-saved-restored: true, + di-variable: '', di-expression: '', di-location: '' } + - { id: 2, name: '', type: spill-slot, offset: -12, size: 4, alignment: 4, + stack-id: 0, callee-saved-register: '$r5', callee-saved-restored: true, + di-variable: '', di-expression: '', di-location: '' } + - { id: 3, name: '', type: spill-slot, offset: -16, size: 4, alignment: 4, + stack-id: 0, callee-saved-register: '$r4', callee-saved-restored: true, + di-variable: '', di-expression: '', di-location: '' } +constants: +body: | + bb.0.entry: + successors: %bb.1(0x40000000), %bb.2(0x40000000) + + $sp = frame-setup STMDB_UPD $sp, 14, $noreg, killed $r4, killed $r5, killed $r11, killed $lr + frame-setup CFI_INSTRUCTION def_cfa_offset 16 + frame-setup CFI_INSTRUCTION offset $lr, -4 + frame-setup CFI_INSTRUCTION offset $r11, -8 + frame-setup CFI_INSTRUCTION offset $r5, -12 + frame-setup CFI_INSTRUCTION offset $r4, -16 + DBG_VALUE debug-use $r0, debug-use $noreg, !13, !DIExpression(), debug-location !16 + DBG_VALUE debug-use $r0, 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 + CMPri renamable $r0, 10, 14, $noreg, implicit-def $cpsr, debug-location !21 + Bcc %bb.2, 13, killed $cpsr, debug-location !21 + + bb.1.if.end: + BL @externFunc, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit killed $r0, implicit-def $sp, implicit-def dead $r0, debug-location !27 + DBG_VALUE 1, debug-use $noreg, !14, !DIExpression(), debug-location !17 + $r0 = MOVi 1, 14, $noreg, $noreg, debug-location !26 + $sp = LDMIA_UPD $sp, 14, $noreg, def $r4, def $r5, def $r11, def $lr, debug-location !26 + BX_RET 14, $noreg, implicit killed $r0, debug-location !26 + + bb.2.if.else: + renamable $r4 = ADDri killed renamable $r0, 10, 14, $noreg, $noreg, debug-location !22 + DBG_VALUE debug-use $r4, debug-use $noreg, !13, !DIExpression(), debug-location !16 + $r0 = MOVr $r4, 14, $noreg, $noreg, debug-location !24 + BL @externFunc2, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit killed $r0, implicit-def $sp, implicit-def $r0, debug-location !24 + $r5 = MOVr killed $r0, 14, $noreg, $noreg, debug-location !24 + DBG_VALUE debug-use $r5, debug-use $noreg, !15, !DIExpression(), debug-location !18 + DBG_VALUE debug-use $r5, debug-use $noreg, !14, !DIExpression(), debug-location !17 + $r0 = MOVr $r4, 14, $noreg, $noreg, debug-location !25 + BL @externFunc, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit killed $r0, implicit-def $sp, implicit-def dead $r0, debug-location !25 + $r0 = MOVr killed $r5, 14, $noreg, $noreg, debug-location !26 + ; Instruction bellow is added in order to test moving variable's value from one register to another. + $r5 = MOVr killed $r4, 14, $noreg, $noreg, debug-location !26 + $sp = LDMIA_UPD $sp, 14, $noreg, def $r4, def $r5, def $r11, def $lr, debug-location !26 + BX_RET 14, $noreg, implicit killed $r0, debug-location !26 + +... 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,286 @@ +# RUN: llc -run-pass=livedebugvalues %s -o - | FileCheck %s +# +# This test tests tracking variables value transferring from one register to another. +# This example is altered additionally in order to test transferring from one float register +# to another. The altered instructions are labeled bellow. +# +# CHECK: ![[ARG1:.*]] = !DILocalVariable(name: "arg1" +# CHECK: ![[ARG2:.*]] = !DILocalVariable(name: "arg2" +# CHECK: DBG_VALUE debug-use $s0_64, debug-use $noreg, ![[ARG2]], !DIExpression(), debug-location +# CHECK: $s1_64 = OR64 killed $s0_64, $zero_64, debug-location +# CHECK-NEXT: DBG_VALUE debug-use $s1_64, debug-use $noreg, ![[ARG2]], !DIExpression(), debug-location +# CHECK: DBG_VALUE debug-use $f24, debug-use $noreg, ![[ARG1]], !DIExpression(), debug-location +# CHECK: $f26 = FMOV_S killed $f24, debug-location +# CHECK-NEXT: DBG_VALUE debug-use $f26, 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 float @foo(float %arg1, i32 signext %arg2) local_unnamed_addr !dbg !8 { + entry: + call void @llvm.dbg.value(metadata float %arg1, metadata !14, metadata !DIExpression()), !dbg !19 + call void @llvm.dbg.value(metadata i32 %arg2, metadata !15, metadata !DIExpression()), !dbg !20 + call void @llvm.dbg.value(metadata float 0.000000e+00, metadata !16, metadata !DIExpression()), !dbg !21 + call void @llvm.dbg.value(metadata float 0.000000e+00, metadata !17, metadata !DIExpression()), !dbg !22 + call void @llvm.dbg.value(metadata i32 0, metadata !18, metadata !DIExpression()), !dbg !23 + %conv = fpext float %arg1 to double, !dbg !24 + %cmp = fcmp ogt double %conv, 1.012310e+01, !dbg !26 + br i1 %cmp, label %if.then, label %if.else, !dbg !27 + + if.then: ; preds = %entry + %call = tail call float @externFunc(float %arg1), !dbg !28 + call void @llvm.dbg.value(metadata float 0x3FF522D0E0000000, metadata !16, metadata !DIExpression()), !dbg !21 + %call5 = tail call i32 @externFunc3(i32 signext %arg2), !dbg !30 + call void @llvm.dbg.value(metadata i32 %call5, metadata !18, metadata !DIExpression()), !dbg !23 + %conv6 = sitofp i32 %call5 to float, !dbg !31 + %add7 = fadd float %conv6, 0x3FF522D0E0000000, !dbg !32 + call void @llvm.dbg.value(metadata float %add7, metadata !16, metadata !DIExpression()), !dbg !21 + br label %if.end, !dbg !33 + + if.else: ; preds = %entry + %add8 = fadd float %arg1, 1.000000e+01, !dbg !34 + call void @llvm.dbg.value(metadata float %add8, metadata !14, metadata !DIExpression()), !dbg !19 + %call9 = tail call float @externFunc2(float %add8), !dbg !36 + call void @llvm.dbg.value(metadata float %call9, metadata !16, metadata !DIExpression()), !dbg !21 + %call10 = tail call i32 @externFunc4(i32 signext %arg2), !dbg !37 + call void @llvm.dbg.value(metadata i32 %call10, metadata !18, metadata !DIExpression()), !dbg !23 + %conv11 = sitofp i32 %call10 to float, !dbg !38 + %add12 = fadd float %call9, %conv11, !dbg !39 + call void @llvm.dbg.value(metadata float %add12, metadata !16, metadata !DIExpression()), !dbg !21 + %call14 = tail call float @externFunc(float %add8), !dbg !40 + br label %if.end + + if.end: ; preds = %if.else, %if.then + %local.0 = phi float [ %add7, %if.then ], [ %add12, %if.else ] + call void @llvm.dbg.value(metadata float %local.0, metadata !16, metadata !DIExpression()), !dbg !21 + ret float %local.0, !dbg !41 + } + + declare float @externFunc(float) local_unnamed_addr + + declare i32 @externFunc3(i32 signext) local_unnamed_addr + + declare float @externFunc2(float) local_unnamed_addr + + declare i32 @externFunc4(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: 6, type: !9, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !13) + !9 = !DISubroutineType(types: !10) + !10 = !{!11, !11, !12} + !11 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) + !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !13 = !{!14, !15, !16, !17, !18} + !14 = !DILocalVariable(name: "arg1", arg: 1, scope: !8, file: !1, line: 6, type: !11) + !15 = !DILocalVariable(name: "arg2", arg: 2, scope: !8, file: !1, line: 6, type: !12) + !16 = !DILocalVariable(name: "local", scope: !8, file: !1, line: 7, type: !11) + !17 = !DILocalVariable(name: "result", scope: !8, file: !1, line: 8, type: !11) + !18 = !DILocalVariable(name: "delta", scope: !8, file: !1, line: 9, type: !12) + !19 = !DILocation(line: 6, column: 17, scope: !8) + !20 = !DILocation(line: 6, column: 27, scope: !8) + !21 = !DILocation(line: 7, column: 8, scope: !8) + !22 = !DILocation(line: 8, column: 8, scope: !8) + !23 = !DILocation(line: 9, column: 13, scope: !8) + !24 = !DILocation(line: 10, column: 6, scope: !25) + !25 = distinct !DILexicalBlock(scope: !8, file: !1, line: 10, column: 6) + !26 = !DILocation(line: 10, column: 11, scope: !25) + !27 = !DILocation(line: 10, column: 6, scope: !8) + !28 = !DILocation(line: 11, column: 13, scope: !29) + !29 = distinct !DILexicalBlock(scope: !25, file: !1, line: 10, column: 22) + !30 = !DILocation(line: 13, column: 25, scope: !29) + !31 = !DILocation(line: 14, column: 12, scope: !29) + !32 = !DILocation(line: 14, column: 9, scope: !29) + !33 = !DILocation(line: 15, column: 2, scope: !29) + !34 = !DILocation(line: 17, column: 8, scope: !35) + !35 = distinct !DILexicalBlock(scope: !25, file: !1, line: 16, column: 7) + !36 = !DILocation(line: 18, column: 11, scope: !35) + !37 = !DILocation(line: 19, column: 11, scope: !35) + !38 = !DILocation(line: 20, column: 12, scope: !35) + !39 = !DILocation(line: 20, column: 9, scope: !35) + !40 = !DILocation(line: 22, column: 13, scope: !35) + !41 = !DILocation(line: 25, column: 2, scope: !8) + +... +--- +name: foo +alignment: 3 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: false +registers: +liveins: + - { reg: '$f12', virtual-reg: '' } + - { reg: '$a1_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: '$d25_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: '$d24_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: '$ra_64', callee-saved-restored: true, + di-variable: '', di-expression: '', di-location: '' } + - { id: 3, name: '', type: spill-slot, offset: -32, size: 8, alignment: 8, + stack-id: 0, callee-saved-register: '$s0_64', callee-saved-restored: true, + di-variable: '', di-expression: '', di-location: '' } +constants: + - id: 0 + value: 'double 1.012310e+01' + alignment: 8 + isTargetSpecific: false + - id: 1 + value: 'float 1.000000e+01' + alignment: 4 + isTargetSpecific: false + - id: 2 + value: float 0x3FF522D0E0000000 + alignment: 4 + isTargetSpecific: false +body: | + bb.0.entry: + successors: %bb.1(0x40000000), %bb.2(0x40000000) + + $sp_64 = DADDiu $sp_64, -32 + CFI_INSTRUCTION def_cfa_offset 32 + SDC164 killed $d25_64, $sp_64, 24 :: (store 8 into %stack.0) + SDC164 killed $d24_64, $sp_64, 16 :: (store 8 into %stack.1) + SD killed $ra_64, $sp_64, 8 :: (store 8 into %stack.2) + SD killed $s0_64, $sp_64, 0 :: (store 8 into %stack.3) + CFI_INSTRUCTION offset $d26_64, -8 + CFI_INSTRUCTION offset $d25_64, -4 + CFI_INSTRUCTION offset $d25_64, -16 + CFI_INSTRUCTION offset $d24_64, -12 + CFI_INSTRUCTION offset $ra_64, -24 + CFI_INSTRUCTION offset $s0_64, -32 + DBG_VALUE debug-use $f12, debug-use $noreg, !14, !DIExpression(), debug-location !19 + DBG_VALUE debug-use $a1_64, debug-use $noreg, !15, !DIExpression(), debug-location !20 + DBG_VALUE 0, debug-use $noreg, !18, !DIExpression(), debug-location !23 + DBG_VALUE float 0.000000e+00, debug-use $noreg, !17, !DIExpression(), debug-location !22 + DBG_VALUE float 0.000000e+00, debug-use $noreg, !16, !DIExpression(), debug-location !21 + DBG_VALUE debug-use $s0, debug-use $noreg, !15, !DIExpression(), debug-location !20 + DBG_VALUE debug-use $s0_64, debug-use $noreg, !15, !DIExpression(), debug-location !20 + DBG_VALUE debug-use $f12, debug-use $noreg, !14, !DIExpression(), debug-location !19 + renamable $d0_64 = CVT_D64_S renamable $f12, debug-location !24 + renamable $at_64 = LUi64 target-flags(mips-highest) %const.0 + renamable $at_64 = DADDiu killed renamable $at_64, target-flags(mips-higher) %const.0 + renamable $at_64 = DSLL killed renamable $at_64, 16 + renamable $at_64 = DADDiu killed renamable $at_64, target-flags(mips-abs-hi) %const.0 + renamable $at_64 = DSLL killed renamable $at_64, 16 + renamable $d1_64 = LDC164 killed renamable $at_64, target-flags(mips-abs-lo) %const.0, debug-location !26 :: (load 8 from constant-pool) + FCMP_D64 killed renamable $d0_64, killed renamable $d1_64, 7, implicit-def $fcc0, debug-location !26 + BC1T killed $fcc0, %bb.2, implicit-def $at, debug-location !27 { + $s0_64 = OR64 $a1_64, $zero_64 + } + + bb.1.if.then: + successors: %bb.3(0x80000000) + + JAL @externFunc, csr_n64, implicit-def dead $ra, implicit $f12, implicit-def $sp, implicit-def dead $f0, debug-location !28 { + NOP debug-location !28 + } + DBG_VALUE float 0x3FF522D0E0000000, debug-use $noreg, !16, !DIExpression(), debug-location !21 + JAL @externFunc3, csr_n64, implicit-def dead $ra, implicit $a0_64, implicit-def $sp, implicit-def $v0, debug-location !30 { + renamable $a0_64 = SLL64_32 renamable $s0, implicit $s0_64, debug-location !30 + } + DBG_VALUE debug-use $v0, debug-use $noreg, !18, !DIExpression(), debug-location !23 + $f0 = MTC1 killed $v0, debug-location !31 + $f0 = CVT_S_W killed $f0, debug-location !31 + ; This instruction is inserted additionally in order to test moving from one register to another + $s1_64 = OR64 killed $s0_64, $zero_64, debug-location !31 + renamable $at_64 = LUi64 target-flags(mips-highest) %const.2 + renamable $at_64 = DADDiu killed renamable $at_64, target-flags(mips-higher) %const.2 + renamable $at_64 = DSLL killed renamable $at_64, 16 + renamable $at_64 = DADDiu killed renamable $at_64, target-flags(mips-abs-hi) %const.2 + renamable $at_64 = DSLL killed renamable $at_64, 16 + renamable $f1 = LWC1 killed renamable $at_64, target-flags(mips-abs-lo) %const.2, debug-location !32 :: (load 4 from constant-pool) + DBG_VALUE debug-use $f0, debug-use $noreg, !16, !DIExpression(), debug-location !21 + J %bb.3, implicit-def dead $at, debug-location !33 { + renamable $f0 = FADD_S killed renamable $f0, killed renamable $f1, debug-location !32 + } + + bb.2.if.else: + successors: %bb.3(0x80000000) + + renamable $at_64 = LUi64 target-flags(mips-highest) %const.1 + renamable $at_64 = DADDiu killed renamable $at_64, target-flags(mips-higher) %const.1 + renamable $at_64 = DSLL killed renamable $at_64, 16 + renamable $at_64 = DADDiu killed renamable $at_64, target-flags(mips-abs-hi) %const.1 + renamable $at_64 = DSLL killed renamable $at_64, 16 + renamable $f0 = LWC1 killed renamable $at_64, target-flags(mips-abs-lo) %const.1, debug-location !34 :: (load 4 from constant-pool) + renamable $f24 = FADD_S killed renamable $f12, killed renamable $f0, debug-location !34 + DBG_VALUE debug-use $f24, debug-use $noreg, !14, !DIExpression(), debug-location !19 + JAL @externFunc2, csr_n64, implicit-def dead $ra, implicit $f12, implicit-def $sp, implicit-def $f0, debug-location !36 { + $f12 = FMOV_S $f24, debug-location !36 + } + $f25 = FMOV_S $f0, debug-location !36 + DBG_VALUE debug-use $f25, debug-use $noreg, !16, !DIExpression(), debug-location !21 + JAL @externFunc4, csr_n64, implicit-def dead $ra, implicit $a0_64, implicit-def $sp, implicit-def $v0, debug-location !37 { + renamable $a0_64 = SLL64_32 renamable $s0, implicit killed $s0_64, debug-location !37 + } + $s0 = OR $v0, $zero, debug-location !37 + DBG_VALUE debug-use $s0, debug-use $noreg, !18, !DIExpression(), debug-location !23 + JAL @externFunc, csr_n64, implicit-def dead $ra, implicit $f12, implicit-def $sp, implicit-def dead $f0, debug-location !40 { + $f12 = FMOV_S $f24, debug-location !40 + } + $f0 = MTC1 killed $s0, debug-location !38 + $f0 = CVT_S_W killed $f0, debug-location !38 + renamable $f0 = FADD_S renamable $f25, killed renamable $f0, debug-location !39 + ; This instruction is inserted additionally in order to test moving variable's value from one float register to another. + $f26 = FMOV_S killed $f24, debug-location !40 + DBG_VALUE debug-use $f0, debug-use $noreg, !16, !DIExpression(), debug-location !21 + + bb.3.if.end: + DBG_VALUE debug-use $f0, debug-use $noreg, !16, !DIExpression(), debug-location !21 + $s0_64 = LD $sp_64, 0, debug-location !41 :: (load 8 from %stack.3) + $ra_64 = LD $sp_64, 8, debug-location !41 :: (load 8 from %stack.2) + $d24_64 = LDC164 $sp_64, 16, debug-location !41 :: (load 8 from %stack.1) + $d25_64 = LDC164 $sp_64, 24, debug-location !41 :: (load 8 from %stack.0) + PseudoReturn64 undef $ra_64, implicit $f0, debug-location !41 { + $sp_64 = DADDiu $sp_64, 32 + } + +... Index: test/DebugInfo/MIR/X86/live-debug-values-reg-copy.mir =================================================================== --- /dev/null +++ test/DebugInfo/MIR/X86/live-debug-values-reg-copy.mir @@ -0,0 +1,227 @@ +# RUN: llc -run-pass=livedebugvalues %s -o - | FileCheck %s +# +# This test tests tracking variables value transferring from one register to another. +# This example is altered additionally in order to test transferring from one float register +# to another. The altered instructions are labeled bellow. +# +# CHECK: ![[ARG1:.*]] = !DILocalVariable(name: "arg1" +# CHECK: DBG_VALUE debug-use $ebx, debug-use $noreg, ![[ARG1]], !DIExpression(), debug-location +# CHECK: $r12d = MOV32rr killed $ebx, implicit-def $r12 +# CHECK-NEXT: DBG_VALUE debug-use $r12, debug-use $noreg, ![[ARG1]], !DIExpression(), debug-location +--- | + ; ModuleID = 'live-debug-values-reg-copy.ll' + source_filename = "live-debug-values-reg-copy.c" + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-linux-gnu" + + define dso_local i32 @foo(i32 %arg1) local_unnamed_addr !dbg !7 { + entry: + %local1 = alloca i32, align 4 + call void @llvm.dbg.value(metadata i32 %arg1, metadata !12, metadata !DIExpression()), !dbg !15 + %0 = bitcast i32* %local1 to i8*, !dbg !16 + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0), !dbg !16 + call void @llvm.dbg.value(metadata i32* %local1, metadata !13, metadata !DIExpression()), !dbg !17 + call void @init(i32* nonnull %local1), !dbg !18 + %1 = load i32, i32* %local1, align 4, !dbg !19, !tbaa !20 + call void @llvm.dbg.value(metadata i32 %1, metadata !13, metadata !DIExpression()), !dbg !17 + %add = add nsw i32 %1, %arg1, !dbg !24 + %call = call i32 @coeficient(i32 %add), !dbg !25 + call void @llvm.dbg.value(metadata i32 %call, metadata !14, metadata !DIExpression()), !dbg !26 + %cmp = icmp sgt i32 %call, 32, !dbg !27 + br i1 %cmp, label %if.then, label %if.else, !dbg !29 + + if.then: ; preds = %entry + %call1 = call i32 @externFunc(i32 %arg1), !dbg !30 + %2 = load i32, i32* %local1, align 4, !dbg !32, !tbaa !20 + call void @llvm.dbg.value(metadata i32 %2, metadata !13, metadata !DIExpression()), !dbg !17 + %add2 = add nsw i32 %2, %call1, !dbg !32 + call void @llvm.dbg.value(metadata i32 %add2, metadata !13, metadata !DIExpression()), !dbg !17 + br label %if.end, !dbg !33 + + if.else: ; preds = %entry + %call3 = call i32 @externFunc2(i32 %arg1), !dbg !34 + %3 = load i32, i32* %local1, align 4, !dbg !36, !tbaa !20 + call void @llvm.dbg.value(metadata i32 %3, metadata !13, metadata !DIExpression()), !dbg !17 + %add4 = add nsw i32 %3, %call3, !dbg !36 + call void @llvm.dbg.value(metadata i32 %add4, metadata !13, metadata !DIExpression()), !dbg !17 + br label %if.end + + if.end: ; preds = %if.else, %if.then + %storemerge = phi i32 [ %add4, %if.else ], [ %add2, %if.then ] + %4 = bitcast i32* %local1 to i8* + call void @llvm.dbg.value(metadata i32 %storemerge, metadata !13, metadata !DIExpression()), !dbg !17 + %mul = shl nsw i32 %arg1, 2, !dbg !37 + %add5 = add nsw i32 %storemerge, %mul, !dbg !38 + call void @llvm.dbg.value(metadata i32 %add5, metadata !13, metadata !DIExpression()), !dbg !17 + %mul6 = mul nsw i32 %add5, %call, !dbg !39 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %4), !dbg !40 + ret i32 %mul6, !dbg !41 + } + + ; Function Attrs: argmemonly nounwind + declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #0 + + declare dso_local void @init(i32*) local_unnamed_addr + + declare dso_local i32 @coeficient(i32) local_unnamed_addr + + declare dso_local i32 @externFunc(i32) local_unnamed_addr + + declare dso_local i32 @externFunc2(i32) local_unnamed_addr + + ; Function Attrs: argmemonly nounwind + declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #0 + + ; Function Attrs: nounwind readnone speculatable + declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) #2 + + attributes #0 = { argmemonly nounwind } + attributes #1 = { nounwind readnone speculatable } + attributes #2 = { nounwind } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3, !4, !5} + !llvm.ident = !{!6} + + !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-values-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 = !{!"clang version 7.0.0 "} + !7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 6, type: !8, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !11) + !8 = !DISubroutineType(types: !9) + !9 = !{!10, !10} + !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !11 = !{!12, !13, !14} + !12 = !DILocalVariable(name: "arg1", arg: 1, scope: !7, file: !1, line: 6, type: !10) + !13 = !DILocalVariable(name: "local1", scope: !7, file: !1, line: 7, type: !10) + !14 = !DILocalVariable(name: "coef", scope: !7, file: !1, line: 9, type: !10) + !15 = !DILocation(line: 6, column: 13, scope: !7) + !16 = !DILocation(line: 7, column: 2, scope: !7) + !17 = !DILocation(line: 7, column: 6, scope: !7) + !18 = !DILocation(line: 8, column: 2, scope: !7) + !19 = !DILocation(line: 9, column: 31, scope: !7) + !20 = !{!21, !21, i64 0} + !21 = !{!"int", !22, i64 0} + !22 = !{!"omnipotent char", !23, i64 0} + !23 = !{!"Simple C/C++ TBAA"} + !24 = !DILocation(line: 9, column: 37, scope: !7) + !25 = !DILocation(line: 9, column: 20, scope: !7) + !26 = !DILocation(line: 9, column: 13, scope: !7) + !27 = !DILocation(line: 10, column: 18, scope: !28) + !28 = distinct !DILexicalBlock(scope: !7, file: !1, line: 10, column: 13) + !29 = !DILocation(line: 10, column: 13, scope: !7) + !30 = !DILocation(line: 11, column: 26, scope: !31) + !31 = distinct !DILexicalBlock(scope: !28, file: !1, line: 10, column: 24) + !32 = !DILocation(line: 11, column: 23, scope: !31) + !33 = !DILocation(line: 12, column: 3, scope: !31) + !34 = !DILocation(line: 14, column: 26, scope: !35) + !35 = distinct !DILexicalBlock(scope: !28, file: !1, line: 13, column: 7) + !36 = !DILocation(line: 14, column: 23, scope: !35) + !37 = !DILocation(line: 16, column: 13, scope: !7) + !38 = !DILocation(line: 16, column: 9, scope: !7) + !39 = !DILocation(line: 17, column: 20, scope: !7) + !40 = !DILocation(line: 18, column: 1, scope: !7) + !41 = !DILocation(line: 17, column: 9, scope: !7) + +... +--- +name: foo +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +registers: +liveins: + - { reg: '$edi', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 24 + offsetAdjustment: 0 + maxAlignment: 4 + adjustsStack: true + hasCalls: true + stackProtector: '' + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + savePoint: '' + restorePoint: '' +fixedStack: + - { id: 0, type: spill-slot, offset: -24, size: 8, alignment: 8, stack-id: 0, + callee-saved-register: '$rbx', callee-saved-restored: true } + - { id: 1, type: spill-slot, offset: -16, size: 8, alignment: 16, stack-id: 0, + callee-saved-register: '$rbp', callee-saved-restored: true } +stack: + - { id: 0, name: local1, type: default, offset: -28, size: 4, alignment: 4, + stack-id: 0, callee-saved-register: '', callee-saved-restored: true, + di-variable: '', di-expression: '', di-location: '' } +constants: +body: | + bb.0.entry: + successors: %bb.1(0x40000000), %bb.2(0x40000000) + liveins: $edi, $rbp, $rbx + + frame-setup PUSH64r killed $rbp, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 16 + frame-setup PUSH64r killed $rbx, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 24 + frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 32 + CFI_INSTRUCTION offset $rbx, -24 + CFI_INSTRUCTION offset $rbp, -16 + DBG_VALUE debug-use $edi, debug-use $noreg, !12, !DIExpression(), debug-location !15 + $ebx = MOV32rr $edi, implicit-def $rbx + DBG_VALUE debug-use $ebx, debug-use $noreg, !12, !DIExpression(), debug-location !15 + renamable $rdi = LEA64r $rsp, 1, $noreg, 4, $noreg + DBG_VALUE $rsp, 0, !13, !DIExpression(DW_OP_plus_uconst, 4), debug-location !17 + CALL64pcrel32 @init, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, debug-location !18 + renamable $edi = MOV32rm $rsp, 1, $noreg, 4, $noreg :: (dereferenceable load 4 from %ir.local1, !tbaa !20) + renamable $edi = ADD32rr killed renamable $edi, renamable $ebx, implicit-def dead $eflags, debug-location !24 + CALL64pcrel32 @coeficient, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax, debug-location !25 + $ebp = MOV32rr $eax, debug-location !25 + DBG_VALUE debug-use $ebp, debug-use $noreg, !14, !DIExpression(), debug-location !26 + $edi = MOV32rr $ebx, debug-location !34 + CMP32ri8 renamable $ebp, 33, implicit-def $eflags, debug-location !27 + JL_1 %bb.2, implicit killed $eflags, debug-location !29 + + bb.1.if.then: + successors: %bb.3(0x80000000) + liveins: $ebp, $edi + + CALL64pcrel32 @externFunc, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax, debug-location !30 + JMP_1 %bb.3 + + bb.2.if.else: + successors: %bb.3(0x80000000) + liveins: $ebp, $edi + + CALL64pcrel32 @externFunc2, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax, debug-location !34 + + bb.3.if.end: + liveins: $ebp, $ebx, $eax + ; Instruction bellow is added in order to test moving variable's value from one register to another. + $r12d = MOV32rr killed $ebx, implicit-def $r12 + renamable $eax = KILL $eax, implicit-def $rax + renamable $eax = ADD32rm renamable $eax, $rsp, 1, $noreg, 4, $noreg, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax :: (dereferenceable load 4 from %ir.local1, !tbaa !20) + DBG_VALUE debug-use $eax, debug-use $noreg, !13, !DIExpression(), debug-location !17 + renamable $eax = LEA64_32r killed renamable $rax, 4, killed renamable $r12, 0, $noreg, debug-location !38 + DBG_VALUE debug-use $eax, debug-use $noreg, !13, !DIExpression(), debug-location !17 + renamable $eax = IMUL32rr killed renamable $eax, killed renamable $ebp, implicit-def dead $eflags, debug-location !39 + $rsp = frame-destroy ADD64ri8 $rsp, 8, implicit-def dead $eflags, debug-location !41 + $rbx = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !41 + $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !41 + RETQ $eax, debug-location !41 + +... 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<