Index: include/llvm/CodeGen/MachineInstr.h =================================================================== --- include/llvm/CodeGen/MachineInstr.h +++ include/llvm/CodeGen/MachineInstr.h @@ -65,7 +65,10 @@ FrameSetup = 1 << 0, // Instruction is used as a part of // function frame setup code. BundledPred = 1 << 1, // Instruction has bundled predecessors. - BundledSucc = 1 << 2 // Instruction has bundled successors. + BundledSucc = 1 << 2, // Instruction has bundled successors. + PreserveDbgValLoc = 1 << 3 // Preserve the older location of the + // variable with this DBG_VALUE MI. + }; private: const MCInstrDesc *MCID; // Instruction descriptor. @@ -153,10 +156,18 @@ /// Set a MI flag. void setFlag(MIFlag Flag) { + if (Flag == PreserveDbgValLoc) + assert (isDebugValue() && + "PreserveDbgValLoc flag cannot be set for a non-DBG_VALUE instruction!"); + Flags |= (uint8_t)Flag; } void setFlags(unsigned flags) { + if (flags & PreserveDbgValLoc) + assert (isDebugValue() && + "PreserveDbgValLoc flag cannot be set for a non-DBG_VALUE instruction!"); + // Filter out the automatically maintained flags. unsigned Mask = BundledPred | BundledSucc; Flags = (Flags & Mask) | (flags & ~Mask); Index: include/llvm/Target/TargetInstrInfo.h =================================================================== --- include/llvm/Target/TargetInstrInfo.h +++ include/llvm/Target/TargetInstrInfo.h @@ -938,6 +938,11 @@ return false; } + /// Return true if the specified opcode is a move opcode + virtual bool isMoveOpcode(unsigned Opc) const { + return false; + } + /// Return true if the specified instruction can be predicated. /// By default, this returns true for every instruction with a /// PredicateOperand. Index: lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h =================================================================== --- lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h +++ lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h @@ -12,6 +12,7 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/raw_ostream.h" namespace llvm { @@ -37,19 +38,24 @@ typedef MapVector InstrRangesMap; private: + /// The VarInstrRange map will have multiple open ranges because of the + /// PreserveDbgValLoc flag. This means startInstrRange, endInstrRange and + /// other related outines will need to handle multiple open ranges. InstrRangesMap VarInstrRanges; public: void startInstrRange(InlinedVariable Var, const MachineInstr &MI); - void endInstrRange(InlinedVariable Var, const MachineInstr &MI); - // Returns register currently describing @Var. If @Var is currently - // unaccessible or is not described by a register, returns 0. - unsigned getRegisterForVar(InlinedVariable Var) const; + void endInstrRange(InlinedVariable Var, unsigned Reg, const MachineInstr &MI); + /// Returns registers currently describing @Var i.e @Var is currently + /// unaccessible or is not described by a register will not be in @RegSet. + void getRegistersForVar(InlinedVariable Var, + SmallVectorImpl &RegSet) const; bool empty() const { return VarInstrRanges.empty(); } void clear() { VarInstrRanges.clear(); } InstrRangesMap::const_iterator begin() const { return VarInstrRanges.begin(); } InstrRangesMap::const_iterator end() const { return VarInstrRanges.end(); } + void print(raw_ostream &Out) const; }; void calculateDbgValueHistory(const MachineFunction *MF, Index: lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp +++ lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp @@ -33,40 +33,58 @@ return MI.getOperand(0).isReg() ? MI.getOperand(0).getReg() : 0; } +// \brief Start a new instr range from @MI for @Var void DbgValueHistoryMap::startInstrRange(InlinedVariable Var, const MachineInstr &MI) { // Instruction range should start with a DBG_VALUE instruction for the // variable. assert(MI.isDebugValue() && "not a DBG_VALUE"); auto &Ranges = VarInstrRanges[Var]; - if (!Ranges.empty() && Ranges.back().second == nullptr && - Ranges.back().first->isIdenticalTo(&MI)) { - DEBUG(dbgs() << "Coalescing identical DBG_VALUE entries:\n" - << "\t" << Ranges.back().first << "\t" << MI << "\n"); - return; + for (auto &R : Ranges) { + if ((R.second == nullptr) && (R.first->getParent() == MI.getParent()) && + (R.first->isIdenticalTo(&MI)) && + (R.first->getFlag(MachineInstr::PreserveDbgValLoc) == + MI.getFlag(MachineInstr::PreserveDbgValLoc)) ) { + DEBUG(dbgs() << "Coalescing identical DBG_VALUE entries:\n" + << R.first << "\t" << MI << "\n"); + return; + } } Ranges.push_back(std::make_pair(&MI, nullptr)); } -void DbgValueHistoryMap::endInstrRange(InlinedVariable Var, +// \brief End the instr range at @MI for @Var with @Reg +void DbgValueHistoryMap::endInstrRange(InlinedVariable Var, unsigned Reg, const MachineInstr &MI) { auto &Ranges = VarInstrRanges[Var]; - // Verify that the current instruction range is not yet closed. - assert(!Ranges.empty() && Ranges.back().second == nullptr); - // For now, instruction ranges are not allowed to cross basic block - // boundaries. - assert(Ranges.back().first->getParent() == MI.getParent()); - Ranges.back().second = &MI; + bool FoundRange = false; // Found atleast one range to end + // Search through Ranges whose start is Reg and is not yet closed + for (auto &R : Ranges) { + if ((Reg == isDescribedByReg(*R.first)) && (R.second == nullptr) && + (R.first->getParent() == MI.getParent()) ) { + // For now, instruction ranges are not allowed to cross basic block + // boundaries. A new DBG_VALUE instruction in the following basic block + // will start a new range. + R.second = &MI; + FoundRange = true; + } + } + assert(FoundRange && "No valid ranged to end!"); } -unsigned DbgValueHistoryMap::getRegisterForVar(InlinedVariable Var) const { +// \brief Build a set of registers which are in open ranges and return +// in \param RegSet. +void DbgValueHistoryMap::getRegistersForVar(InlinedVariable Var, + SmallVectorImpl &RegSet) const { const auto &I = VarInstrRanges.find(Var); if (I == VarInstrRanges.end()) - return 0; + return; + const auto &Ranges = I->second; - if (Ranges.empty() || Ranges.back().second != nullptr) - return 0; - return isDescribedByReg(*Ranges.back().first); + for (const auto R : Ranges) + if (R.second == nullptr) + if (unsigned Reg = isDescribedByReg(*R.first)) + RegSet.push_back(Reg); } namespace { @@ -75,14 +93,33 @@ typedef std::map> RegDescribedVarsMap; } +// Print @RegDescirbedVarsMap to ostream. +void printRegDescribedVarsMap(raw_ostream &Out, + const RegDescribedVarsMap &RegVars) { + Out << "RegDescribedVarsMap:"; + for (const auto &RV : RegVars) { + Out << "\nReg: " << RV.first << ":\t"; + for (const auto &IV : RV.second) { + if (IV.second != nullptr) + Out << "<" << IV.first->getName() << "," << *IV.second << ">, "; + else + Out << "<" << IV.first->getName() << ", ... " << ">, "; + } + } + Out << "\n\n"; +} + // \brief Claim that @Var is not described by @RegNo anymore. static void dropRegDescribedVar(RegDescribedVarsMap &RegVars, unsigned RegNo, InlinedVariable Var) { const auto &I = RegVars.find(RegNo); - assert(RegNo != 0U && I != RegVars.end()); + assert(RegNo != 0U); + if (I == RegVars.end()) + return; auto &VarSet = I->second; const auto &VarPos = std::find(VarSet.begin(), VarSet.end(), Var); - assert(VarPos != VarSet.end()); + if (VarPos == VarSet.end()) + return; VarSet.erase(VarPos); // Don't keep empty sets in a map to keep it as small as possible. if (VarSet.empty()) @@ -94,7 +131,10 @@ InlinedVariable Var) { assert(RegNo != 0U); auto &VarSet = RegVars[RegNo]; - assert(std::find(VarSet.begin(), VarSet.end(), Var) == VarSet.end()); + if (std::find(VarSet.begin(), VarSet.end(), Var) != VarSet.end()) { + // Ignore if already found + return; + } VarSet.push_back(Var); } @@ -107,7 +147,7 @@ // Iterate over all variables described by this register and add this // instruction to their history, clobbering it. for (const auto &Var : I->second) - HistMap.endInstrRange(Var, ClobberingInstr); + HistMap.endInstrRange(Var, I->first, ClobberingInstr); RegVars.erase(I); } @@ -181,6 +221,27 @@ } } +// \brief Routine to print @VarInstrRanges to ostream. +void DbgValueHistoryMap::print(raw_ostream &Out) const { + Out << "DbgValueHistoryMap:\n"; + for (const auto VIRi : VarInstrRanges) { + const InlinedVariable &IV = VIRi.first; + const InstrRanges &IR = VIRi.second; + if (IV.second != nullptr) + Out << "<" << IV.first->getName() << "," << *IV.second << "> = \n"; + else + Out << "<" << IV.first->getName() << ", ... " << "> = \n"; + for (const auto IRi : IR) { + assert(IRi.first != nullptr); + if (IRi.second != nullptr) + Out << "\tFrom: " << *IRi.first << "\tTo: " << *IRi.second; + else + Out << "\tFrom: " << *IRi.first << "\tTo: ... " << "\n"; + Out << "\n"; + } + } +} + void llvm::calculateDbgValueHistory(const MachineFunction *MF, const TargetRegisterInfo *TRI, DbgValueHistoryMap &Result) { @@ -190,6 +251,7 @@ RegDescribedVarsMap RegVars; for (const auto &MBB : *MF) { for (const auto &MI : MBB) { + DEBUG(dbgs() << "MBB: " << MBB.getName() << ": "; MI.dump();); if (!MI.isDebugValue()) { // Not a DBG_VALUE instruction. It may clobber registers which describe // some variables. @@ -197,6 +259,9 @@ if (ChangingRegs.test(RegNo)) clobberRegisterUses(RegVars, RegNo, Result, MI); }); + DEBUG(dbgs() << "After clobbering a non-DBG_VALUE instr: "; MI.dump(); + Result.print(dbgs()); + printRegDescribedVarsMap(dbgs(), RegVars)); continue; } @@ -209,13 +274,22 @@ "Expected inlined-at fields to agree"); InlinedVariable Var(RawVar, MI.getDebugLoc()->getInlinedAt()); - if (unsigned PrevReg = Result.getRegisterForVar(Var)) - dropRegDescribedVar(RegVars, PrevReg, Var); + if (!MI.getFlag(MachineInstr::PreserveDbgValLoc)) { + // This DBG_VALUE instr preserves previous locations + SmallVector RegSet; + Result.getRegistersForVar(Var, RegSet); + for (auto R : RegSet) { + dropRegDescribedVar(RegVars, R, Var); + } + } Result.startInstrRange(Var, MI); if (unsigned NewReg = isDescribedByReg(MI)) addRegDescribedVar(RegVars, NewReg, Var); + DEBUG(dbgs() << "After starting InstrRange: "; MI.dump(); + Result.print(dbgs()); + printRegDescribedVarsMap(dbgs(), RegVars)); } // Make sure locations for register-described variables are valid only @@ -224,9 +298,17 @@ if (!MBB.empty() && &MBB != &MF->back()) { for (auto I = RegVars.begin(), E = RegVars.end(); I != E;) { auto CurElem = I++; // CurElem can be erased below. - if (ChangingRegs.test(CurElem->first)) + if (ChangingRegs.test(CurElem->first)) { clobberRegisterUses(RegVars, CurElem, Result, MBB.back()); + } } } + DEBUG(dbgs() << "End of bb: "; MBB.back().dump(); + Result.print(dbgs()); + printRegDescribedVarsMap(dbgs(), RegVars)); } + + DEBUG(dbgs() << "End of calculateDbgValueHistory():\n"; + Result.print(dbgs()); + printRegDescribedVarsMap(dbgs(), RegVars)); } Index: lib/CodeGen/AsmPrinter/DebugLocEntry.h =================================================================== --- lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -14,6 +14,7 @@ #include "llvm/IR/DebugInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MachineLocation.h" +#include "llvm/Support/raw_ostream.h" namespace llvm { class AsmPrinter; @@ -75,6 +76,25 @@ const DIExpression *getExpression() const { return Expression; } friend bool operator==(const Value &, const Value &); friend bool operator<(const Value &, const Value &); + void print(raw_ostream &Out) const { + switch (EntryKind) { + case E_Location: + { + MachineLocation Loc = getLoc(); + if (Loc.isReg()) + Out << "E_Location:Register " << Loc.getReg(); + else + Out << "E_Location:Indirect " << Loc.getReg() << "[" << + Loc.getOffset() << "]"; + break; + } + case E_Integer: Out << "E_Integer " << getInt(); break; + case E_ConstantFP: Out << "E_ConstantFP " << getConstantFP(); break; + case E_ConstantInt: Out << "E_ConstantInt " << getConstantInt(); break; + default: break; + } + Out << "\n"; + } }; private: Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -866,10 +866,19 @@ const MCSymbol *EndLabel; if (End != nullptr) EndLabel = getLabelAfterInsn(End); - else if (std::next(I) == Ranges.end()) - EndLabel = Asm->getFunctionEnd(); - else - EndLabel = getLabelBeforeInsn(std::next(I)->first); + else { + // This is an open range - terminate at the next non-preserving DBG_VALUE + // instr or at function end + auto NPi = std::next(I), NPe = Ranges.end(); + for ( ;NPi != NPe; NPi++) { + if (!(NPi->first->getFlag(MachineInstr::PreserveDbgValLoc))) { + EndLabel = getLabelBeforeInsn(NPi->first); + break; + } + } + if (NPi == NPe) + EndLabel = Asm->getFunctionEnd(); + } assert(EndLabel && "Forgot label after instruction ending a range!"); DEBUG(dbgs() << "DotDebugLoc: " << *Begin << "\n"); @@ -902,9 +911,12 @@ // DebugLocEntries. auto CurEntry = DebugLoc.rbegin(); DEBUG({ - dbgs() << CurEntry->getValues().size() << " Values:\n"; - for (auto &Value : CurEntry->getValues()) - Value.getExpression()->dump(); + dbgs() << "From " << *StartLabel << " to " << *EndLabel << "\n\t"; + dbgs() << CurEntry->getValues().size() << " Value(s):\n"; + for (auto &Value : CurEntry->getValues()) { + dbgs() << "\t\t"; + Value.print(dbgs()); + } dbgs() << "-----\n"; }); Index: lib/CodeGen/ExtendDebugRangeLocation.cpp =================================================================== --- lib/CodeGen/ExtendDebugRangeLocation.cpp +++ lib/CodeGen/ExtendDebugRangeLocation.cpp @@ -1,4 +1,4 @@ -//===-- ExtendDebugRangeLocation.cpp - Fixup Debug Value MIs -----------------------===// +//===-- ExtendDebugRangeLocation.cpp - Extend Debug Value MIs -------------===// // // The LLVM Compiler Infrastructure // @@ -7,20 +7,19 @@ // //===----------------------------------------------------------------------===// // -// Fixup DBG_VALUE MachineInstructions -// a. Fixup debug ranges by inserting new DBG_VALUE instructions at bb join +// a. Extend debug ranges by inserting new DBG_VALUE instructions at bb join // points. Current idea is to not build any true ranges here. Only temporary // ranges are built to calculate DBG_VALUE at join points. True ranges are // built in DbgValueHistoryCalculator. // b. Try to infer the presence of a debug variable at multiple locations from -// move instructions (TODO). +// move instructions. // c. Add missing DBG_VALUE instructions, if possible (TODO). // d. Any DBG_VALUE instruction related code. // // This is a separate pass from DbgValueHistoryCalculator because the // MachineFunction(MF) is to be modified (like adding a new DBG_VALUE MI while -// handling multiple locations etc) and DbgValueHistoryCalculator has a `const' -// MF. Also it would be neat to do the above fixups in this separate pass and +// handling multiple locations etc) but DbgValueHistoryCalculator has a `const' +// MF. Also it would be neat to do the above changes in this separate pass and // allow the existing DbgValueHistoryCalculator logic to take over. // //===----------------------------------------------------------------------===// @@ -93,6 +92,11 @@ void ExtendRanges(MachineFunction &MF); + // Member variables and functions for inferring Multiple Locations + void HandleMoveForMultipleLocations(MachineInstr &MI); + + void InferMultipleLocations(MachineFunction &MF); + MachineBasicBlock::iterator RemoveRedundantDbgVals(MachineInstr &MI); void clearExtendDebugRangeLocationData(); }; @@ -292,14 +296,16 @@ "Expected inlined-at fields to agree"); InlinedVariable Var(RawVar, MI.getDebugLoc()->getInlinedAt()); - // End all previous ranges of Var - VarLocList::iterator ORi = OpenRanges.begin(), ORe = OpenRanges.end(); - while (ORi != ORe) { - VarLocList::iterator ORiSave = ORi; - ORi++; - if (Var == ORiSave->first.second) { - OpenRanges.erase(ORiSave); - ORi = OpenRanges.begin(), ORe = OpenRanges.end(); + // End all previous ranges of Var, if PreserveDbgValLoc is not set + if (!MI.getFlag(MachineInstr::PreserveDbgValLoc)) { + VarLocList::iterator ORi = OpenRanges.begin(), ORe = OpenRanges.end(); + while (ORi != ORe) { + VarLocList::iterator ORiSave = ORi; + ORi++; + if (Var == ORiSave->first.second) { + OpenRanges.erase(ORiSave); + ORi = OpenRanges.begin(), ORe = OpenRanges.end(); + } } } // Add Var to OpenRanges from this DBG_VALUE @@ -466,12 +472,84 @@ DEBUG(print("Final OutgoingLocs", dbgs())); } +//===----------------------------------------------------------------------===// +// Inferring Multiple Locations Implementation +//===----------------------------------------------------------------------===// + +// Insert a new DBG_VALUE instruction with PreserveDbgValLoc set when a copy +// instruction is seen. @MI is the move instruction. +void ExtendDebugRangeLocation::HandleMoveForMultipleLocations(MachineInstr &MI){ + // Identify the source variable related to source operand and insert a + // DBG_VALUE instruction indicating the source variable to be in dst reg. + + if (MI.getNumOperands() != 2) { + DEBUG(dbgs() << "Expected 2 operands for `mov' instr.\n"); + return; + } + if (!(MI.getOperand(0).isReg() && MI.getOperand(1).isReg())) { + DEBUG(dbgs() << "Currently handles only register move instructions.\n"); + return; + } + + // TODO: Ignore creating a new DBG_VALUE instr if the dst reg is a isKill()? + + // If the source register is mapped to a Var then insert a new DBG_VALUE instr + // with preserve flag and new location as destination register. The source reg + // mapping is obtained from OpenRanges and there could be multiple Vars mapped + // to the source register - in which case, multiple DBG_VALUE instrs with + // preserve loc flag are inserted for each Var. + for (auto &OR : OpenRanges) { + if (MI.getOperand(1).getReg() == isDescribedByReg(*OR.second)) { + const MachineInstr *DMI = OR.second; + MachineBasicBlock::iterator MBBI(MI); + MachineInstr *DV = BuildMI(*MI.getParent(), ++MBBI, DMI->getDebugLoc(), + DMI->getDesc(), DMI->isIndirectDebugValue(), + MI.getOperand(0).getReg(), 0, + DMI->getDebugVariable(), DMI->getDebugExpression()); + if (DMI->isIndirectDebugValue()) + DV->getOperand(1).setImm(DMI->getOperand(1).getImm()); + DV->setFlag(MachineInstr::PreserveDbgValLoc); + DEBUG(dbgs() << "Inserted: "; DV->dump();); + ++NumInserted; + } + } +} + +// Insert a DBG_VALUE instruction with PreserveDbgValLoc set, if the variable +// is found to be present in multiple locations. +// TODO: Currently, we infer only when we see copies +void ExtendDebugRangeLocation::InferMultipleLocations(MachineFunction &MF) { + + DEBUG(dbgs() << "\nMultiple Locations\n"); + + clearExtendDebugRangeLocationData(); + + for (auto &MBB : MF) { + OpenRanges.clear(); + MachineBasicBlock::iterator MBBi = MBB.instr_begin(),MBBe = MBB.instr_end(); + while (MBBi != MBBe) { + MachineInstr &MI = *MBBi; + transfer(MI, true); // transfer MI through the bb + if (TII->isMoveOpcode(MI.getOpcode())) { + DEBUG(print("Before handling move in Multiple Locations", dbgs())); + HandleMoveForMultipleLocations(MI); + // Reset iterators + MBBi = MachineBasicBlock::iterator(MI), MBBe = MBB.instr_end(); + } + MBBi++; + } + DEBUG(print("Multiple Locations after an mbb", dbgs())); + } +} + bool ExtendDebugRangeLocation::runOnMachineFunction(MachineFunction &MF) { TRI = MF.getSubtarget().getRegisterInfo(); TII = MF.getSubtarget().getInstrInfo(); ExtendRanges(MF); + InferMultipleLocations(MF); + // Remove Redundant DBG_VALUE instructions for (auto &MBB : MF) { for (auto MBBI = MBB.begin(), MBBE = MBB.end(); MBBI != MBBE; ) { Index: lib/CodeGen/MachineInstr.cpp =================================================================== --- lib/CodeGen/MachineInstr.cpp +++ lib/CodeGen/MachineInstr.cpp @@ -1735,13 +1735,15 @@ } bool HaveSemi = false; - const unsigned PrintableFlags = FrameSetup; + const unsigned PrintableFlags = FrameSetup | PreserveDbgValLoc; if (Flags & PrintableFlags) { if (!HaveSemi) OS << ";"; HaveSemi = true; OS << " flags: "; if (Flags & FrameSetup) OS << "FrameSetup"; + if (Flags & PreserveDbgValLoc) + OS << " PreserveDbgValLoc"; } if (!memoperands_empty()) { Index: lib/Target/X86/X86InstrInfo.h =================================================================== --- lib/Target/X86/X86InstrInfo.h +++ lib/Target/X86/X86InstrInfo.h @@ -390,6 +390,8 @@ bool ReverseBranchCondition(SmallVectorImpl &Cond) const override; + bool isMoveOpcode(unsigned Opc) const override; + /// isSafeToMoveRegClassDefs - Return true if it's safe to move a machine /// instruction that defines the specified register class. bool isSafeToMoveRegClassDefs(const TargetRegisterClass *RC) const override; Index: lib/Target/X86/X86InstrInfo.cpp =================================================================== --- lib/Target/X86/X86InstrInfo.cpp +++ lib/Target/X86/X86InstrInfo.cpp @@ -2331,6 +2331,32 @@ return true; } +// Return true if the specified opcode @Opc is a move opcode +bool X86InstrInfo::isMoveOpcode(unsigned Opc) const { + switch (Opc) { + default: return false; + case X86::MOV16ri: case X86::MOV16mi: + case X86::MOV16rr: case X86::MOV16mr: + case X86::MOV32ri: case X86::MOV32mi: + case X86::MOV32rr: case X86::MOV32mr: + case X86::MOV64ri32: case X86::MOV64mi32: + case X86::MOV64rr: case X86::MOV64mr: + case X86::MOV8ri: case X86::MOV8mi: + case X86::MOV8rr: case X86::MOV8mr: + case X86::MOV8rr_NOREX: case X86::MOV8mr_NOREX: + case X86::MOVAPDrr: case X86::MOVAPDmr: + case X86::MOVAPSrr: case X86::MOVAPSmr: + case X86::MOVDQArr: case X86::MOVDQAmr: + case X86::MOVPDI2DIrr: case X86::MOVPDI2DImr: + case X86::MOVPQIto64rr: case X86::MOVPQI2QImr: + case X86::MOVSDto64rr: case X86::MOVSDto64mr: + case X86::MOVSS2DIrr: case X86::MOVSS2DImr: + case X86::MOVUPDrr: case X86::MOVUPDmr: + case X86::MOVUPSrr: case X86::MOVUPSmr: + return true; + } +} + bool X86InstrInfo::isSafeToClobberEFLAGS(MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { MachineBasicBlock::iterator E = MBB.end(); Index: test/CodeGen/X86/2010-05-26-DotDebugLoc.ll =================================================================== --- test/CodeGen/X86/2010-05-26-DotDebugLoc.ll +++ test/CodeGen/X86/2010-05-26-DotDebugLoc.ll @@ -66,8 +66,14 @@ ; The variable bar:myvar changes registers after the first movq. ; It is cobbered by popq %rbx ; CHECK: movq -; CHECK-NEXT: [[LABEL:Ltmp[0-9]*]] +; CHECK-NEXT: [[LABEL1:Ltmp[0-9]*]] +; CHECK: movl +; CHECK-NEXT: [[LABEL2:Ltmp[0-9]*]] + +; The variable bar:myvar is moved again to other register ; CHECK: .loc 1 19 0 +; CHECK-NEXT: movq +; CHECK-NEXT: [[LABEL3:Ltmp[0-9]*]] ; CHECK: popq ; CHECK-NEXT: [[CLOBBER:Ltmp[0-9]*]] @@ -75,14 +81,18 @@ ; CHECK: Ldebug_loc0: ; CHECK-NEXT: [[SET1:.*]] = Lfunc_begin0-Lfunc_begin0 ; CHECK-NEXT: .quad [[SET1]] -; CHECK-NEXT: [[SET2:.*]] = [[LABEL]]-Lfunc_begin0 +; CHECK-NEXT: [[SET2:.*]] = [[LABEL2]]-Lfunc_begin0 ; CHECK-NEXT: .quad [[SET2]] ; CHECK-NEXT: .short 1 ## Loc expr size ; CHECK-NEXT: .byte 85 -; CHECK-NEXT: [[SET3:.*]] = [[LABEL]]-Lfunc_begin0 +; CHECK-NEXT: [[SET3:.*]] = [[LABEL1]]-Lfunc_begin0 ; CHECK-NEXT: .quad [[SET3]] ; CHECK-NEXT: [[SET4:.*]] = [[CLOBBER]]-Lfunc_begin0 ; CHECK-NEXT: .quad [[SET4]] ; CHECK-NEXT: .short 1 ## Loc expr size ; CHECK-NEXT: .byte 83 +; CHECK-NEXT: [[SET5:.*]] = [[LABEL3]]-Lfunc_begin0 +; CHECK-NEXT: .quad [[SET5]] +; CHECK: .short 1 ## Loc expr size +; CHECK-NEXT: .byte 80 !38 = !{i32 1, !"Debug Info Version", i32 3} Index: test/DebugInfo/MIR/X86/multiple-locations.mir =================================================================== --- /dev/null +++ test/DebugInfo/MIR/X86/multiple-locations.mir @@ -0,0 +1,136 @@ +# RUN: llc -run-pass=extend-dbg-range-loc -march=x86-64 -o /dev/null %s | FileCheck %s + +# Test the presence of a variable at multiple locations +# Generated from the source file inc.c: +# #include +# int inc(int n) { +# n++; +# printf("n(inc)2: %d\n", n); +# return n; +# } +# with clang -g -emit-llvm inc.c -c -o ml.bc +# then opt -O3 -S -o multiple-locations.ll ml.bc +# then llc -stop-after stackmap-liveness multiple-locations.ll -o /dev/null > multiple-locations.mir +# This test case is tested with DWARF information under +# llvm/test/DebugInfo/mulitple-locations.ll and present here for testing under +# MIR->MIR serialization. +# +# The PreserveDbgValLoc flag that signifies the presence of a variable at +# multiple locations cannot be seen here. So only the correct ordering of the +# expected instructions is tested. +# +# CHECK: DBG_VALUE debug-use %edi, debug-use _, !11, !12, debug-location !13 +# CHECK-NEXT: %ebx = MOV32rr %edi +# CHECK-NEXT: DBG_VALUE debug-use %ebx, debug-use _, !11, !12, debug-location !13 +# CHECK-NOT: DBG_VALUE + + +--- | + ; ModuleID = 'multiple-locations.ll' + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-linux-gnu" + + @.str = private unnamed_addr constant [13 x i8] c"n(inc)2: %d\0A\00", align 1 + + ; Function Attrs: nounwind uwtable + define i32 @inc(i32 %n) #0 { + entry: + tail call void @llvm.dbg.value(metadata i32 %n, i64 0, metadata !11, metadata !12), !dbg !13 + %inc = add nsw i32 %n, 1, !dbg !14 + tail call void @llvm.dbg.value(metadata i32 %inc, i64 0, metadata !11, metadata !12), !dbg !13 + %call = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str, i64 0, i64 0), i32 %inc) #3, !dbg !15 + ret i32 %inc, !dbg !16 + } + + ; Function Attrs: nounwind + declare i32 @printf(i8* nocapture readonly, ...) #1 + + ; Function Attrs: nounwind readnone + declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #2 + + attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" } + attributes #1 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" } + attributes #2 = { nounwind readnone } + attributes #3 = { nounwind } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!8, !9} + !llvm.ident = !{!10} + + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.0 (trunk 243841)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3) + !1 = !DIFile(filename: "inc.c", directory: "/home/vt/vikram/newTests") + !2 = !{} + !3 = !{!4} + !4 = !DISubprogram(name: "inc", scope: !1, file: !1, line: 2, type: !5, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, function: i32 (i32)* @inc, variables: !2) + !5 = !DISubroutineType(types: !6) + !6 = !{!7, !7} + !7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) + !8 = !{i32 2, !"Dwarf Version", i32 4} + !9 = !{i32 2, !"Debug Info Version", i32 3} + !10 = !{!"clang version 3.8.0 (trunk 243841)"} + !11 = !DILocalVariable(name: "n", arg: 1, scope: !4, file: !1, line: 2, type: !7) + !12 = !DIExpression() + !13 = !DILocation(line: 2, column: 13, scope: !4) + !14 = !DILocation(line: 3, column: 4, scope: !4) + !15 = !DILocation(line: 4, column: 3, scope: !4) + !16 = !DILocation(line: 5, column: 3, scope: !4) + +... +--- +name: inc +alignment: 4 +exposesReturnsTwice: false +hasInlineAsm: false +isSSA: false +tracksRegLiveness: true +tracksSubRegLiveness: false +liveins: + - { reg: '%edi' } +calleeSavedRegisters: [ '%bh', '%bl', '%bp', '%bpl', '%bx', '%ebp', '%ebx', + '%rbp', '%rbx', '%r12', '%r13', '%r14', '%r15', + '%r12b', '%r13b', '%r14b', '%r15b', '%r12d', '%r13d', + '%r14d', '%r15d', '%r12w', '%r13w', '%r14w', '%r15w' ] +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 24 + offsetAdjustment: -8 + maxAlignment: 0 + adjustsStack: true + hasCalls: true + maxCallFrameSize: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false +fixedStack: + - { id: 0, type: spill-slot, offset: -24, size: 8, alignment: 8, callee-saved-register: '%rbx' } + - { id: 1, type: spill-slot, offset: -16, size: 8, alignment: 16 } +body: | + bb.0.entry: + liveins: %edi, %rbx, %rbx, %rbp + + frame-setup PUSH64r killed %rbp, implicit-def %rsp, implicit %rsp + CFI_INSTRUCTION .cfi_def_cfa_offset 16 + CFI_INSTRUCTION .cfi_offset %rbp, -16 + %rbp = frame-setup MOV64rr %rsp + CFI_INSTRUCTION .cfi_def_cfa_register %rbp + frame-setup PUSH64r killed %rbx, implicit-def %rsp, implicit %rsp + frame-setup PUSH64r undef %rax, implicit-def %rsp, implicit %rsp + CFI_INSTRUCTION .cfi_offset %rbx, -24 + DBG_VALUE debug-use %edi, debug-use _, !11, !12, debug-location !13 + %ebx = MOV32rr %edi + DBG_VALUE debug-use %ebx, debug-use _, !11, !12, debug-location !13 + %ebx = INC32r killed %ebx, implicit-def dead %eflags, debug-location !14 + dead undef %edi = MOV32ri64 @.str, implicit-def %rdi, debug-location !15 + dead %eax = XOR32rr undef %eax, undef %eax, implicit-def dead %eflags, implicit-def %al, debug-location !15 + %esi = MOV32rr %ebx, debug-location !15 + CALL64pcrel32 @printf, csr_64, implicit %rsp, implicit %rdi, implicit %esi, implicit killed %al, implicit-def %rsp, implicit-def dead %eax, debug-location !15 + %eax = MOV32rr killed %ebx, debug-location !16 + %rsp = ADD64ri8 %rsp, 8, implicit-def dead %eflags, debug-location !16 + %rbx = POP64r implicit-def %rsp, implicit %rsp, debug-location !16 + %rbp = POP64r implicit-def %rsp, implicit %rsp, debug-location !16 + RETQ killed %eax, debug-location !16 + +... Index: test/DebugInfo/X86/pieces-1.ll =================================================================== --- test/DebugInfo/X86/pieces-1.ll +++ test/DebugInfo/X86/pieces-1.ll @@ -17,14 +17,22 @@ ; CHECK: .debug_loc contents: ; -; 0x0000000000000000 - 0x0000000000000006: rdi, piece 0x00000008, rsi, piece 0x00000004 +; Initially, s.a (piece 0x08) is in rdi and s.b (piece 0x04) is in rsi. +; Then rsi (s.b) is moved to rax. +; Finally, rbp-8 contains s.a and rax contains s.b. + +; 0x0000000000000000 - 0x000000000000000a: rdi, piece 0x00000008, rsi, piece 0x00000004 ; CHECK: Beginning address offset: 0x0000000000000000 -; CHECK: Ending address offset: [[LTMP3:.*]] -; CHECK: Location description: 55 93 08 54 93 04 -; 0x0000000000000006 - 0x0000000000000008: rbp-8, piece 0x00000008, rax, piece 0x00000004 ) -; CHECK: Beginning address offset: [[LTMP3]] ; CHECK: Ending address offset: [[END:.*]] -; CHECK: Location description: 76 78 93 08 54 93 04 +; CHECK: Location description: 55 93 08 54 93 04 +; 0x0000000000000006 - 0x000000000000000a: rdi, piece 0x00000008, rax, piece 0x00000004 +; CHECK: Beginning address offset: 0x0000000000000006 +; CHECK: Ending address offset: [[END]] +; CHECK: Location description: 55 93 08 50 93 04 +; 0x000000000000000a - 0x000000000000000c: rbp-8, piece 0x00000008, rax, piece 0x00000004 +; CHECK: Beginning address offset: [[END]] +; CHECK: Ending address offset: 0x000000000000000c +; CHECK: Location description: 76 78 93 08 50 93 04 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.9.0" Index: test/DebugInfo/X86/pieces-3.ll =================================================================== --- test/DebugInfo/X86/pieces-3.ll +++ test/DebugInfo/X86/pieces-3.ll @@ -16,20 +16,39 @@ ; } ; ; CHECK: DW_TAG_formal_parameter [3] -; CHECK-NEXT: DW_AT_location [DW_FORM_data4] ([[LOC:.*]]) +; CHECK-NEXT: DW_AT_location [DW_FORM_data4] ([[LOC1:.*]]) ; CHECK-NEXT: DW_AT_name {{.*}}"outer" ; CHECK: DW_TAG_variable -; rsi, piece 0x00000004 -; CHECK-NEXT: DW_AT_location [DW_FORM_block1] {{.*}} 54 93 04 +; rsi, piece 0x00000004 now resides at two locations given by LOC2 +; CHECK-NEXT: DW_AT_location [DW_FORM_data4] ([[LOC2:.*]]) ; CHECK-NEXT: "i1" ; ; CHECK: .debug_loc -; CHECK: [[LOC]]: -; CHECK: Beginning address offset: 0x0000000000000000 -; CHECK: Ending address offset: 0x0000000000000008 +; "outer" variable ranges: +; CHECK: [[LOC1]]: +; CHECK: Beginning address offset: 0x0000000000000000 +; CHECK-NEXT: Ending address offset: 0x0000000000000008 ; rdi, piece 0x00000008, piece 0x00000004, rsi, piece 0x00000004 -; CHECK: Location description: 55 93 08 93 04 54 93 04 +; CHECK-NEXT: Location description: 55 93 08 93 04 54 93 04 + +; CHECK: Beginning address offset: 0x0000000000000006 +; CHECK-NEXT: Ending address offset: 0x0000000000000008 +; rdi, piece 0x00000008, piece 0x00000004, rax, piece 0x00000004 +; CHECK-NEXT: Location description: 55 93 08 93 04 50 93 04 +; +; "i1" ranges: +; CHEC: [[LOC2]]: +; CHECK: Beginning address offset: 0x0000000000000004 +; CHECK-NEXT: Ending address offset: 0x0000000000000008 +; in rsi +; CHECK-NEXT: Location description: 54 93 04 ; +; CHECK: Beginning address offset: 0x0000000000000006 +; CHECK-NEXT: Ending address offset: 0x0000000000000008 +; in rax +; CHECK-NEXT: Location description: 50 93 04 + + ; ModuleID = '/Volumes/Data/llvm/test/DebugInfo/X86/sroasplit-2.ll' target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.9.0" Index: test/DebugInfo/X86/pr19307.ll =================================================================== --- test/DebugInfo/X86/pr19307.ll +++ test/DebugInfo/X86/pr19307.ll @@ -20,6 +20,7 @@ ; Verify that we have proper range in debug_loc section: ; CHECK: .Ldebug_loc{{[0-9]+}}: ; CHECK: DW_OP_breg1 +; CHECK: DW_OP_breg5 ; CHECK: .quad [[START_LABEL]]-.Lfunc_begin0 ; CHECK-NEXT: .quad .Lfunc_end0-.Lfunc_begin0 ; CHECK: DW_OP_breg6 Index: test/DebugInfo/multiple-locations.ll =================================================================== --- /dev/null +++ test/DebugInfo/multiple-locations.ll @@ -0,0 +1,96 @@ +; RUN: llc -filetype=asm %s -o - | FileCheck %s + +; Test the presence of a variable at multiple locations +; Generated from the source file inc.c: +; #include +; int inc(int n) { +; n++; +; printf("n(inc)2: %d\n", n); +; return n; +; } +; with clang -g -emit-llvm inc.c -c -o ml.bc +; then opt -O3 -S -o multiple-locations.ll ml.bc + +; Multiple located variable is inferred from "mov" instructions and they will +; have overlapped ranges - in this case, range for "n", in %ebx is present +; inside the range of %edi. +; +; CHECK: #DEBUG_VALUE: inc:n <- EDI +; +; Move happens here +; CHECK-NEXT: movl %edi, %ebx +; +; Range for "n" in %ebx runs from .Ltmp4 till .Ltmp5 where %ebx is +; incremented (clobbered). +; CHECK-NEXT: [[INNER_START:.Ltmp[0-9]+]] +; CHECK-NEXT: #DEBUG_VALUE: inc:n <- EBX +; CHECK-NEXT: .loc 1 3 4 prologue_end # inc.c:3:4 +; CHECK-NEXT: incl %ebx +; CHECK-NEXT: [[INNER_END:.Ltmp[0-9]+]] +; CHECK-NEXT: .loc 1 4 3 # inc.c:4:3 +; +; Range for %edi which started at .Lfunc_begin0, ends here where it is clobbered +; CHECK-NEXT: movl $.L.str, %edi +; CHECK-NEXT: [[OUTER_END:.Ltmp[0-9]+]] +; +; Now check from .debug_loc section if the ranges overlap. +; %edi (reg5) range is from .Ldebug_loc0 to OUTER_END +; CHECK: .Ldebug_loc0 +; CHECK-NEXT: .quad .Lfunc_begin0-.Lfunc_begin0 +; CHECK-NEXT: .quad [[OUTER_END]]-.Lfunc_begin0 +; CHECK: super-register DW_OP_reg5 +; +; %ebx (reg3) range resides within %edi range. Labels guarantee it. +; CHECK: .quad [[INNER_START]]-.Lfunc_begin0 +; CHECK-NEXT: .quad [[INNER_END]]-.Lfunc_begin0 +; CHECK: super-register DW_OP_reg3 + + +; ModuleID = 'ml.bc' +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@.str = private unnamed_addr constant [13 x i8] c"n(inc)2: %d\0A\00", align 1 + +; Function Attrs: nounwind uwtable +define i32 @inc(i32 %n) #0 { +entry: + tail call void @llvm.dbg.value(metadata i32 %n, i64 0, metadata !11, metadata !12), !dbg !13 + %inc = add nsw i32 %n, 1, !dbg !14 + tail call void @llvm.dbg.value(metadata i32 %inc, i64 0, metadata !11, metadata !12), !dbg !13 + %call = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str, i64 0, i64 0), i32 %inc) #3, !dbg !15 + ret i32 %inc, !dbg !16 +} + +; Function Attrs: nounwind +declare i32 @printf(i8* nocapture readonly, ...) #1 + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #2 + +attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.0 (trunk 243841)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3) +!1 = !DIFile(filename: "inc.c", directory: "/home/vt/vikram/newTests") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "inc", scope: !1, file: !1, line: 2, type: !5, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, function: i32 (i32)* @inc, variables: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !7} +!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!8 = !{i32 2, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{!"clang version 3.8.0 (trunk 243841)"} +!11 = !DILocalVariable(name: "n", arg: 1, scope: !4, file: !1, line: 2, type: !7) +!12 = !DIExpression() +!13 = !DILocation(line: 2, column: 13, scope: !4) +!14 = !DILocation(line: 3, column: 4, scope: !4) +!15 = !DILocation(line: 4, column: 3, scope: !4) +!16 = !DILocation(line: 5, column: 3, scope: !4)