Index: docs/SourceLevelDebugging.rst =================================================================== --- docs/SourceLevelDebugging.rst +++ docs/SourceLevelDebugging.rst @@ -569,6 +569,7 @@ metadata, ;; Type descriptor i32, ;; flags metadata ;; (optional) Reference to inline location + i32, ... ;; (optional) Complex expression (see below) } These descriptors are used to define variables local to a sub program. The @@ -587,6 +588,16 @@ Name the source variable name. Context and line indicate where the variable was defined. Type descriptor defines the declared type of the variable. +Local variables may have a complex address, which may consist of any +combination of ``OpPlus`` and ``OpDeref`` or an ``OpPiece``. The +``OpPlus`` operator takes one i32 argument that is an offset to add to +the address and ``OpDeref`` dereferences the address. The ``OpPiece`` +operator is used for (typically larger aggregate) variables that are +fragmented across several addresses. It takes two i32 arguments, an +offset and a size to describe which piece of the variable is at this +address. + + .. _format_common_intrinsics: Debugger intrinsic functions Index: include/llvm/CodeGen/AsmPrinter.h =================================================================== --- include/llvm/CodeGen/AsmPrinter.h +++ include/llvm/CodeGen/AsmPrinter.h @@ -428,9 +428,18 @@ /// encoding specified. virtual unsigned getISAEncoding() { return 0; } + /// EmitDwarfRegOp - Emit a partial dwarf register operation. + /// \param MLoc the register + /// \param PieceSize size and + /// \param Indirect offset of the piece in bits, if this is one + /// piece of an aggregate value. + void EmitDwarfRegOpPiece(const MachineLocation &MLoc, + unsigned PieceSize, + unsigned PieceOffset) const; + /// EmitDwarfRegOp - Emit dwarf register operation. - virtual void EmitDwarfRegOp(const MachineLocation &MLoc, - bool Indirect) const; + /// \param Indirect whether this is a register-indirect address + virtual void EmitDwarfRegOp(const MachineLocation &MLoc, bool Indirect) const; //===------------------------------------------------------------------===// // Dwarf Lowering Routines Index: include/llvm/CodeGen/MachineInstr.h =================================================================== --- include/llvm/CodeGen/MachineInstr.h +++ include/llvm/CodeGen/MachineInstr.h @@ -23,6 +23,7 @@ #include "llvm/ADT/ilist.h" #include "llvm/ADT/ilist_node.h" #include "llvm/CodeGen/MachineOperand.h" +#include "llvm/DebugInfo.h" #include "llvm/IR/InlineAsm.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/Support/ArrayRecycler.h" @@ -242,6 +243,14 @@ /// DebugLoc getDebugLoc() const { return debugLoc; } + /// getDebugVariable() - Retrun the debug variable referenced by + /// this DBG_VALUE instruction. + DIVariable getDebugVariable() const { + assert( isDebugValue() ); + const MDNode *Var = getOperand(getNumOperands() - 1).getMetadata(); + return DIVariable(Var); + } + /// emitError - Emit an error referring to the source location of this /// instruction. This should only be used for inline assembly that is somehow /// impossible to compile. Other errors should have been handled much Index: include/llvm/DIBuilder.h =================================================================== --- include/llvm/DIBuilder.h +++ include/llvm/DIBuilder.h @@ -85,7 +85,7 @@ public: explicit DIBuilder(Module &M); - enum ComplexAddrKind { OpPlus=1, OpDeref }; + enum ComplexAddrKind { OpPlus=1, OpDeref, OpPiece }; /// finalize - Construct any deferred debug info descriptors. void finalize(); @@ -537,6 +537,16 @@ DIType Ty, ArrayRef Addr, unsigned ArgNo = 0); + /// createVariablePiece - Create a descriptor to describe one part + /// of aggregate variable that is fragmented across multiple Values. + /// + /// @param Variable Variable that is partially represented by this. + /// @param OffsetInBytes Offset of the piece in bytes. + /// @param SizeInBytes Size of the piece in bytes. + DIVariable createVariablePiece(DIVariable Variable, + unsigned OffsetInBytes, + unsigned SizeInBytes); + /// createFunction - Create a new descriptor for the specified subprogram. /// See comments in DISubprogram for descriptions of these fields. /// @param Scope Function scope. Index: include/llvm/DebugInfo.h =================================================================== --- include/llvm/DebugInfo.h +++ include/llvm/DebugInfo.h @@ -676,6 +676,14 @@ /// information for an inlined function arguments. bool isInlinedFnArgument(const Function *CurFn); + /// isVariablePiece - Return whether this is a piece of an aggregate + /// variable. + bool isVariablePiece() const; + /// getPieceOffset - Return the offset of this piece in bytes. + uint64_t getPieceOffset() const; + /// getPieceSize - Return the size of this piece in bytes. + uint64_t getPieceSize() const; + void printExtendedName(raw_ostream &OS) const; }; @@ -770,6 +778,9 @@ /// cleanseInlinedVariable - Remove inlined scope from the variable. DIVariable cleanseInlinedVariable(MDNode *DV, LLVMContext &VMContext); +/// getEntireVariable - Remove OpPiece exprs from the variable. +DIVariable getEntireVariable(const MDNode *DV, LLVMContext &VMContext); + /// Construct DITypeIdentifierMap by going through retained types of each CU. DITypeIdentifierMap generateDITypeIdentifierMap(const NamedMDNode *CU_Nodes); Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -905,34 +905,54 @@ AP.EmitInt8(dwarf::DW_OP_deref); } -// Emit a dwarf (bit_)piece operation. +/// Emit a dwarf (bit_)piece operation. +/// Size an Offset are bits. static void emitDwarfOpPiece(const AsmPrinter &AP, - unsigned Size, unsigned Offset) { - assert(Size > 0); - if (Offset > 0) { + unsigned SizeInBits, + unsigned OffsetInBits) { + assert(SizeInBits > 0); + if (OffsetInBits > 0) { AP.OutStreamer.AddComment("DW_OP_bit_piece"); AP.EmitInt8(dwarf::DW_OP_bit_piece); - AP.OutStreamer.AddComment(Twine(Size)); - AP.EmitULEB128(Size); - AP.OutStreamer.AddComment(Twine(Offset)); - AP.EmitULEB128(Offset); + AP.OutStreamer.AddComment(Twine(SizeInBits)); + AP.EmitULEB128(SizeInBits); + AP.OutStreamer.AddComment(Twine(OffsetInBits)); + AP.EmitULEB128(OffsetInBits); } else { AP.OutStreamer.AddComment("DW_OP_piece"); AP.EmitInt8(dwarf::DW_OP_piece); - unsigned ByteSize = Size / 8; // Assuming 8 bits per byte. + assert( SizeInBits % 8 == 0 ); + unsigned ByteSize = SizeInBits / 8; // Assuming 8 bits per byte. AP.OutStreamer.AddComment(Twine(ByteSize)); AP.EmitULEB128(ByteSize); } } +static void emitDwarfOpShr(const AsmPrinter &AP, + unsigned ShiftBy) { + AP.OutStreamer.AddComment("DW_OP_constu"); + AP.EmitInt8(dwarf::DW_OP_constu); + AP.EmitULEB128(ShiftBy); + AP.OutStreamer.AddComment("DW_OP_shr"); + AP.EmitInt8(dwarf::DW_OP_shr); +} + /// Emit a dwarf register operation by emitting a piece of a /// super-register or by piecing together multiple subregisters. -static void EmitDwarfRegOpPiece(const AsmPrinter &AP, - const MachineLocation &MLoc) { +void AsmPrinter::EmitDwarfRegOpPiece(const MachineLocation &MLoc, + unsigned PieceSizeInBits, + unsigned PieceOffsetInBits) const { + assert(!MLoc.isIndirect()); - const TargetRegisterInfo *TRI = AP.TM.getRegisterInfo(); + const TargetRegisterInfo *TRI = TM.getRegisterInfo(); int Reg = TRI->getDwarfRegNum(MLoc.getReg(), false); + if (Reg >= 0) { + emitDwarfRegOp(*this, Reg); + emitDwarfOpPiece(*this, PieceSizeInBits, PieceOffsetInBits); + return; + } + // Walk up the super-register chain until we find a valid number. for (MCSuperRegIterator SR(MLoc.getReg(), TRI); SR.isValid(); ++SR) { Reg = TRI->getDwarfRegNum(*SR, false); @@ -940,31 +960,41 @@ unsigned Idx = TRI->getSubRegIndex(*SR, MLoc.getReg()); unsigned Size = TRI->getSubRegIdxSize(Idx); unsigned Offset = TRI->getSubRegIdxOffset(Idx); - emitDwarfRegOp(AP, Reg); - emitDwarfOpPiece(AP, Size, Offset); + emitDwarfRegOp(*this, Reg); + if (PieceOffsetInBits == Offset) { + emitDwarfOpPiece(*this, Size, Offset); + } else { + // If this is part of a variable in a sub-register at a + // non-zero offset, we need to manually shift the value into + // place, since the dwarf op_piece describes the part of the + // variable, not the position of the subregister. + emitDwarfOpPiece(*this, Size, PieceOffsetInBits); + if (Offset) + emitDwarfOpShr(*this, Offset); + } return; } } // Otherwise, attempt to find a covering set of sub-register numbers. - unsigned CurPos = 0; + unsigned CurPos = PieceOffsetInBits; for (MCSubRegIterator SR(MLoc.getReg(), TRI); SR.isValid(); ++SR) { Reg = TRI->getDwarfRegNum(*SR, false); if (Reg >= 0) { unsigned Idx = TRI->getSubRegIndex(MLoc.getReg(), *SR); unsigned Size = TRI->getSubRegIdxSize(Idx); - unsigned Offset = TRI->getSubRegIdxOffset(Idx); - emitDwarfRegOp(AP, Reg); - emitDwarfOpPiece(AP, Size, Offset == CurPos ? 0 : Offset); + unsigned Offset = PieceOffsetInBits + TRI->getSubRegIdxOffset(Idx); + emitDwarfRegOp(*this, Reg); + emitDwarfOpPiece(*this, Size, Offset == CurPos ? 0 : Offset); CurPos = Offset+Size; } } - if (CurPos > 0) + if (CurPos != PieceOffsetInBits) // We're done. return; - AP.OutStreamer.AddComment("nop (could not find a dwarf register number)"); - AP.EmitInt8(dwarf::DW_OP_nop); + OutStreamer.AddComment("nop (could not find a dwarf register number)"); + EmitInt8(dwarf::DW_OP_nop); } /// EmitDwarfRegOp - Emit dwarf register operation. @@ -975,7 +1005,7 @@ if (Reg < 0) { if (!Indirect && !MLoc.isIndirect()) - return EmitDwarfRegOpPiece(*this, MLoc); + return EmitDwarfRegOpPiece(MLoc, 0, 0); // FIXME: We have no reasonable way of handling errors in here. The // caller might be in the middle of a dwarf expression. We should Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1253,7 +1253,7 @@ const MCSymbol *FLabel, const MCSymbol *SLabel, const MachineInstr *MI) { - const MDNode *Var = MI->getOperand(MI->getNumOperands() - 1).getMetadata(); + const MDNode *Var = MI->getDebugVariable(); assert(MI->getNumOperands() == 3); if (MI->getOperand(0).isReg()) { @@ -1276,6 +1276,35 @@ llvm_unreachable("Unexpected 3 operand DBG_VALUE instruction!"); } +/// Determine whether two variable pieces overlap. +static bool piecesOverlap(DIVariable P1, DIVariable P2) { + assert(P1.isVariablePiece() && P1.isVariablePiece() && "must be a piece"); + return (P1.getPieceOffset() < P2.getPieceOffset() + P2.getPieceSize() && + P2.getPieceOffset() < P1.getPieceOffset() + P1.getPieceSize()); +} + +typedef SmallVectorImpl::iterator HistoryIter; + +/// The range of a variable piece is truncated if its value is +/// clobbered, or by an overlapping piece. +static HistoryIter +nextOverlappingHistoryEntry(HistoryIter DbgVal, HistoryIter End) { + DIVariable DV0 = (*DbgVal)->getDebugVariable(); + if (!DV0.isVariablePiece()) + return DbgVal+1; + + for (HistoryIter I=DbgVal+1; I != End; ++I) { + if (!*I) continue; + if (!(*I)->isDebugValue()) return I; + + // Clobber or overlap? + DIVariable DVI = (*I)->getDebugVariable(); + if (!DVI.isVariablePiece() || piecesOverlap(DV0, DVI)) + return I; + } + return End; +} + // Find variables for each lexical scope. void DwarfDebug::collectVariableInfo(SmallPtrSet &Processed) { @@ -1296,6 +1325,12 @@ SmallVectorImpl &History = DbgValues[Var]; if (History.empty()) continue; + + DEBUG(dbgs()<< "History for " << *Var << "[ "; + for (HistoryIter HI = History.begin(); HI != History.end(); ++HI) + (*HI)->dump(); + dbgs()<< "]\n"); + const MachineInstr *MInsn = History.front(); DIVariable DV(Var); @@ -1330,11 +1365,15 @@ // Handle multiple DBG_VALUE instructions describing one variable. RegVar->setDotDebugLocOffset(DotDebugLocEntries.size()); - for (SmallVectorImpl::const_iterator - HI = History.begin(), - HE = History.end(); - HI != HE; ++HI) { + // Build the location list. + bool ShareFLabel = false; + const MCSymbol *SLabel, *FLabel = 0; + for (HistoryIter HI = History.begin(), HE = History.end(); HI != HE; ++HI) { const MachineInstr *Begin = *HI; + // Skip over end markers that we already processed. + if (!Begin) continue; + DEBUG(dbgs()<< "Range for " << *Begin->getDebugVariable() + << "beginning at " << *Begin <<"\n"); assert(Begin->isDebugValue() && "Invalid History entry"); // Check if DBG_VALUE is truncating a range. @@ -1343,15 +1382,17 @@ continue; // Compute the range for a register location. - const MCSymbol *FLabel = getLabelBeforeInsn(Begin); - const MCSymbol *SLabel = 0; + if (!ShareFLabel) + FLabel = getLabelBeforeInsn(Begin); + SLabel = 0; - if (HI + 1 == HE) + HistoryIter EndOfRange = nextOverlappingHistoryEntry(HI, HE); + if (EndOfRange == HE) // If Begin is the last instruction in History then its value is valid // until the end of the function. SLabel = FunctionEndSym; else { - const MachineInstr *End = HI[1]; + const MachineInstr *End = *EndOfRange; DEBUG(dbgs() << "DotDebugLoc Pair:\n" << "\t" << *Begin << "\t" << *End << "\n"); if (End->isDebugValue()) @@ -1360,13 +1401,15 @@ // End is a normal instruction clobbering the range. SLabel = getLabelAfterInsn(End); assert(SLabel && "Forgot label after clobber instruction"); - ++HI; + // Mark the end as processed. + *EndOfRange = 0; } } // The value is valid until the next DBG_VALUE or clobber. DotDebugLocEntries.push_back( getDebugLocEntry(Asm, FLabel, SLabel, Begin)); + ShareFLabel = EndOfRange != HI+1; } DotDebugLocEntries.push_back(DotDebugLocEntry()); } @@ -1560,17 +1603,19 @@ assert(MI->getNumOperands() > 1 && "Invalid machine instruction!"); // Keep track of user variables. - const MDNode *Var = - MI->getOperand(MI->getNumOperands() - 1).getMetadata(); + DIVariable Var = MI->getDebugVariable(); // Variable is in a register, we need to check for clobbers. if (isDbgValueInDefinedReg(MI)) LiveUserVar[MI->getOperand(0).getReg()] = Var; - // Check the history of this variable. - SmallVectorImpl &History = DbgValues[Var]; + // Check the history of this variable. A variable may be fragmented + // into multiple pieces, but they still share one history. + DIVariable EntireVar = getEntireVariable(Var, Var->getContext()); + SmallVectorImpl &History = DbgValues[EntireVar]; + if (History.empty()) { - UserVariables.push_back(Var); + UserVariables.push_back(EntireVar); // The first mention of a function argument gets the FunctionBeginSym // label, so arguments are visible when breaking at function entry. DIVariable DV(Var); @@ -1590,6 +1635,12 @@ History.pop_back(); } + if (EntireVar.isVariablePiece()) { + DEBUG(dbgs() << "Adding piece " << *Var << " at " << *MI <<"\n"); + History.push_back(MI); + continue; + } + // Terminate old register assignments that don't reach MI; MachineFunction::const_iterator PrevMBB = Prev->getParent(); if (PrevMBB != I && (!AtBlockEntry || llvm::next(PrevMBB) != I) && @@ -1637,7 +1688,8 @@ LiveUserVar[Reg] = 0; // Was MD last defined by a DBG_VALUE referring to Reg? - DbgValueHistoryMap::iterator HistI = DbgValues.find(Var); + DIVariable EntireVar = getEntireVariable(Var, Var->getContext()); + DbgValueHistoryMap::iterator HistI = DbgValues.find(EntireVar); if (HistI == DbgValues.end()) continue; SmallVectorImpl &History = HistI->second; @@ -2619,8 +2671,37 @@ Asm->EmitDwarfRegOp(Loc, DV.isIndirect()); else { // Complex address entry. + if (DV.isVariablePiece()) { + bool Consecutive = true; + unsigned Offset = 0; + // Collect all the pieces belonging to this variable. + for (; I!=E; ++I) { + DIVariable Var(I->getVariable()); + if (Offset > 0 && + !(Var.isVariable() && + Var.isVariablePiece() && + Var.getName() == DV.getName() && + I->getBeginSym() == Entry.getBeginSym() && + I->getEndSym() == Entry.getEndSym())) { + --I; + break; + } + + if (Var.getPieceOffset() != Offset) + Consecutive = false; + + Offset += Var.getPieceSize(); + + assert(!Var.isIndirect() && "indirect address for piece"); + // Assuming 8 bits per byte. + Asm->EmitDwarfRegOpPiece(I->getLoc(), + Var.getPieceSize()*8, + Var.getPieceOffset()*8); + } + } else { unsigned N = DV.getNumAddrElements(); unsigned i = 0; + if (N >= 2 && DV.getAddrElement(0) == DIBuilder::OpPlus) { if (Loc.getOffset()) { i = 2; @@ -2653,6 +2734,7 @@ } else llvm_unreachable("unknown Opcode found in complex address"); } + } // FIXME: weird indentation here to make the diff more readable. } } // else ... ignore constant fp. There is not any good way to Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -550,6 +550,12 @@ } else if (Element == DIBuilder::OpDeref) { if (!Location.isReg()) addUInt(Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); + } else if (Element == DIBuilder::OpPiece) { + DIVariable Piece = DV.getMInsn()->getDebugVariable(); + assert(Piece.getPieceSize() > 0 && "empty piece"); + addUInt(Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_bit_piece); + addUInt(Loc, dwarf::DW_FORM_data1, Piece.getPieceSize()); + addUInt(Loc, dwarf::DW_FORM_data1, Piece.getPieceOffset()); } else llvm_unreachable("unknown DIBuilder Opcode"); } Index: lib/CodeGen/SelectionDAG/InstrEmitter.cpp =================================================================== --- lib/CodeGen/SelectionDAG/InstrEmitter.cpp +++ lib/CodeGen/SelectionDAG/InstrEmitter.cpp @@ -671,6 +671,8 @@ DenseMap::iterator I = VRBaseMap.find(Op); if (I==VRBaseMap.end()) MIB.addReg(0U); // undef + else if (TargetRegisterInfo::isPhysicalRegister(I->second)) + MIB.addReg(I->second, RegState::Debug); else AddOperand(MIB, Op, (*MIB).getNumOperands(), &II, VRBaseMap, /*IsDebug=*/true, /*IsClone=*/false, /*IsCloned=*/false); Index: lib/CodeGen/SelectionDAG/LegalizeTypes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeTypes.cpp +++ lib/CodeGen/SelectionDAG/LegalizeTypes.cpp @@ -14,7 +14,11 @@ //===----------------------------------------------------------------------===// #include "LegalizeTypes.h" +#include "SDNodeDbgValue.h" #include "llvm/ADT/SetVector.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/DIBuilder.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/DataLayout.h" #include "llvm/Support/CommandLine.h" @@ -775,6 +779,34 @@ Hi = Entry.second; } +/// TransferDbgValues - Transfer SDDbgValues. +static void TransferDbgValues(SelectionDAG &DAG, DIBuilder &DIB, + SDValue From, SDValue To, + unsigned Offset) { + SDNode *FromNode = From.getNode(); + SDNode *ToNode = To.getNode(); + assert(FromNode != ToNode); + ArrayRef DVs = DAG.GetDbgValues(FromNode); + for (ArrayRef::iterator I = DVs.begin(), E = DVs.end(); + I != E; ++I) { + SDDbgValue *Dbg = *I; + + if (Dbg->getKind() == SDDbgValue::SDNODE) { + // Assuming 8 bits / byte. + assert( Offset % 8 == 0 ); + assert( To.getValueSizeInBits() % 8 == 0 ); + DIVariable Var(Dbg->getMDPtr()); + DIVariable Piece = DIB.createVariablePiece(Var, Offset / 8, + To.getValueSizeInBits() / 8); + SDDbgValue *Clone = DAG.getDbgValue(&*Piece, ToNode, To.getResNo(), + Dbg->getOffset(), Dbg->getDebugLoc(), + Dbg->getOrder()); + Dbg->setIsInvalidated(); + DAG.AddDbgValue(Clone, ToNode, false); + } + } +} + void DAGTypeLegalizer::SetExpandedInteger(SDValue Op, SDValue Lo, SDValue Hi) { assert(Lo.getValueType() == @@ -785,6 +817,12 @@ AnalyzeNewValue(Lo); AnalyzeNewValue(Hi); + // Transfer debug values. + const Module *M = DAG.getMachineFunction().getMMI().getModule(); + DIBuilder DIB(*const_cast(M)); + TransferDbgValues(DAG, DIB, Op, Lo, 0); + TransferDbgValues(DAG, DIB, Op, Hi, Lo.getValueSizeInBits()); + // Remember that this is the result of the node. std::pair &Entry = ExpandedIntegers[Op]; assert(Entry.first.getNode() == 0 && "Node already expanded"); Index: lib/CodeGen/SelectionDAG/SelectionDAG.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -6050,7 +6050,7 @@ I != E; ++I) { SDDbgValue *Dbg = *I; if (Dbg->getKind() == SDDbgValue::SDNODE) { - SDDbgValue *Clone = getDbgValue(Dbg->getMDPtr(), ToNode, To.getResNo(), + SDDbgValue *Clone = getDbgValue(Dbg->getMDPtr(), ToNode, Dbg->getResNo(), Dbg->getOffset(), Dbg->getDebugLoc(), Dbg->getOrder()); ClonedDVs.push_back(Clone); Index: lib/IR/DIBuilder.cpp =================================================================== --- lib/IR/DIBuilder.cpp +++ lib/IR/DIBuilder.cpp @@ -1038,6 +1038,22 @@ return DIVariable(MDNode::get(VMContext, Elts)); } +/// createVariablePiece - Create a descriptor to describe one part +/// of aggregate variable that is fragmented across multiple Values. +DIVariable DIBuilder::createVariablePiece(DIVariable Variable, + unsigned OffsetInBytes, + unsigned SizeInBytes) { + assert(SizeInBytes > 0); + SmallVector Elts; + for (unsigned i = 0; i < Variable->getNumOperands(); ++i) + Elts.push_back(Variable->getOperand(i)); + + Elts.push_back(ConstantInt::get(Type::getInt32Ty(VMContext), OpPiece)); + Elts.push_back(ConstantInt::get(Type::getInt32Ty(VMContext), OffsetInBytes)); + Elts.push_back(ConstantInt::get(Type::getInt32Ty(VMContext), SizeInBytes)); + return DIVariable(MDNode::get(VMContext, Elts)); +} + /// createFunction - Create a new descriptor for the specified function. /// FIXME: this is added for dragonegg. Once we update dragonegg /// to call resolve function, this will be removed. Index: lib/IR/DebugInfo.cpp =================================================================== --- lib/IR/DebugInfo.cpp +++ lib/IR/DebugInfo.cpp @@ -17,6 +17,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/Analysis/ValueTracking.h" +#include "llvm/DIBuilder.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instructions.h" @@ -143,6 +144,21 @@ /// getInlinedAt - If this variable is inlined then return inline location. MDNode *DIVariable::getInlinedAt() const { return getNodeField(DbgNode, 7); } +bool DIVariable::isVariablePiece() const { + return hasComplexAddress() && getAddrElement(0) == DIBuilder::OpPiece; +} + +uint64_t DIVariable::getPieceOffset() const { + assert(isVariablePiece()); + return getAddrElement(1); +} +uint64_t DIVariable::getPieceSize() const { + assert(isVariablePiece()); + return getAddrElement(2); +} + + + //===----------------------------------------------------------------------===// // Predicates //===----------------------------------------------------------------------===// @@ -876,6 +892,21 @@ return DIVariable(MDNode::get(VMContext, Elts)); } + +/// getEntireVariable - Remove OpPiece exprs from the variable. +DIVariable llvm::getEntireVariable(const MDNode *MD, LLVMContext &VMContext) { + DIVariable DV(MD); + if (!DV.isVariablePiece()) + return DV; + + SmallVector Elts; + for (unsigned i = 0; i < 9; ++i) + Elts.push_back(DV->getOperand(i)); + + return DIVariable(MDNode::get(VMContext, Elts)); +} + + /// getDISubprogram - Find subprogram that is enclosing this scope. DISubprogram llvm::getDISubprogram(const MDNode *Scope) { DIDescriptor D(Scope); Index: lib/Support/GraphWriter.cpp =================================================================== --- lib/Support/GraphWriter.cpp +++ lib/Support/GraphWriter.cpp @@ -87,7 +87,7 @@ errs() << "Error: " << ErrMsg << "\n"; return false; } - sys::fs::remove(Filename); + //sys::fs::remove(Filename); errs() << " done. \n"; } else { Index: lib/Transforms/Scalar/SROA.cpp =================================================================== --- lib/Transforms/Scalar/SROA.cpp +++ lib/Transforms/Scalar/SROA.cpp @@ -248,6 +248,9 @@ void dump() const; #endif + /// \brief Return the dbg.declare intrinsic describing the alloca. + DbgDeclareInst *getDbgDeclare() const { return DbgDeclare; } + private: template class BuilderBase; class SliceBuilder; @@ -291,6 +294,9 @@ /// want to swap this particular input for undef to simplify the use lists of /// the alloca. SmallVector DeadOperands; + + /// \brief The dbg.declare intrinsic describing the alloca. + DbgDeclareInst *DbgDeclare; }; } @@ -417,6 +423,11 @@ if (!IsOffsetKnown) return PI.setAborted(&SI); + // Make a best effort to find a dbg.declare intrinsic describing + // the alloca by peeking at the next instruction. + if (DbgDeclareInst *DDI=dyn_cast_or_null(SI.getNextNode())) + S.DbgDeclare = DDI; + uint64_t Size = DL.getTypeStoreSize(ValOp->getType()); // If this memory access can be shown to *statically* extend outside the @@ -674,7 +685,9 @@ #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) AI(AI), #endif - PointerEscapingInstr(0) { + PointerEscapingInstr(0), + DbgDeclare(0) +{ SliceBuilder PB(DL, AI, *this); SliceBuilder::PtrInfo PtrI = PB.visitPtr(AI); if (PtrI.isEscaped() || PtrI.isAborted()) { @@ -930,9 +943,10 @@ bool rewritePartition(AllocaInst &AI, AllocaSlices &S, AllocaSlices::iterator B, AllocaSlices::iterator E, int64_t BeginOffset, int64_t EndOffset, - ArrayRef SplitUses); - bool splitAlloca(AllocaInst &AI, AllocaSlices &S); - bool runOnAlloca(AllocaInst &AI); + ArrayRef SplitUses, + DIBuilder &DIB); + bool splitAlloca(AllocaInst &AI, AllocaSlices &S, DIBuilder &DIB); + bool runOnAlloca(AllocaInst &AI, DIBuilder &DIB); void clobberUse(Use &U); void deleteDeadInstructions(SmallPtrSet &DeletedAllocas); bool promoteAllocas(Function &F); @@ -1961,11 +1975,13 @@ // Utility IR builder, whose name prefix is setup for each visited use, and // the insertion point is set to point to the user. IRBuilderTy IRB; + DIBuilder &DIB; public: AllocaSliceRewriter(const DataLayout &DL, AllocaSlices &S, SROA &Pass, AllocaInst &OldAI, AllocaInst &NewAI, uint64_t NewBeginOffset, uint64_t NewEndOffset, + DIBuilder &DIB, bool IsVectorPromotable = false, bool IsIntegerPromotable = false) : DL(DL), S(S), Pass(Pass), OldAI(OldAI), NewAI(NewAI), @@ -1981,7 +1997,8 @@ : 0), BeginOffset(), EndOffset(), IsSplittable(), IsSplit(), OldUse(), OldPtr(), IsUsedByRewrittenSpeculatableInstructions(false), - IRB(NewAI.getContext(), ConstantFolder()) { + IRB(NewAI.getContext(), ConstantFolder()), + DIB(DIB) { if (VecTy) { assert((DL.getTypeSizeInBits(ElementTy) % 8) == 0 && "Only multiple-of-8 sized vector elements are viable"); @@ -2215,7 +2232,18 @@ V = convertValue(DL, IRB, V, NewAllocaTy); StoreInst *Store = IRB.CreateAlignedStore(V, &NewAI, NewAI.getAlignment()); Pass.DeadInsts.insert(&SI); - (void)Store; + + // Split up the debug information if this stores only part of the value. + if (DbgDeclareInst *DbgDecl = S.getDbgDeclare()) { + DIVariable Var(DbgDecl->getVariable()); + uint64_t Size = EndOffset - BeginOffset; + if (Var.getType().getSizeInBits() < Size*8 /* Assuming 8 Bits/Byte */) { + DIVariable Piece = DIB.createVariablePiece(Var, BeginOffset, Size); + DIB.insertDbgValueIntrinsic(V, 0, Piece, Store) + ->setDebugLoc(DbgDecl->getDebugLoc()); + Pass.DeadInsts.insert(DbgDecl); + } + } DEBUG(dbgs() << " to: " << *Store << "\n"); return true; } @@ -3069,7 +3097,8 @@ bool SROA::rewritePartition(AllocaInst &AI, AllocaSlices &S, AllocaSlices::iterator B, AllocaSlices::iterator E, int64_t BeginOffset, int64_t EndOffset, - ArrayRef SplitUses) { + ArrayRef SplitUses, + DIBuilder &DIB) { assert(BeginOffset < EndOffset); uint64_t SliceSize = EndOffset - BeginOffset; @@ -3141,7 +3170,7 @@ unsigned NumUses = 0; AllocaSliceRewriter Rewriter(*DL, S, *this, AI, *NewAI, BeginOffset, - EndOffset, IsVectorPromotable, + EndOffset, DIB, IsVectorPromotable, IsIntegerPromotable); bool Promotable = true; for (ArrayRef::const_iterator SUI = SplitUses.begin(), @@ -3234,7 +3263,7 @@ /// \brief Walks the slices of an alloca and form partitions based on them, /// rewriting each of their uses. -bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &S) { +bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &S, DIBuilder &DIB) { if (S.begin() == S.end()) return false; @@ -3283,8 +3312,8 @@ // we'll have to rewrite uses and erase old split uses. if (BeginOffset < MaxEndOffset) { // Rewrite a sequence of overlapping slices. - Changed |= - rewritePartition(AI, S, SI, SJ, BeginOffset, MaxEndOffset, SplitUses); + Changed |= rewritePartition(AI, S, SI, SJ, BeginOffset, MaxEndOffset, + SplitUses, DIB); ++NumPartitions; removeFinishedSplitUses(SplitUses, MaxSplitUseEndOffset, MaxEndOffset); @@ -3324,7 +3353,7 @@ SJ == SE ? MaxSplitUseEndOffset : SJ->beginOffset(); Changed |= rewritePartition(AI, S, SJ, SJ, MaxEndOffset, PostSplitEndOffset, - SplitUses); + SplitUses, DIB); ++NumPartitions; if (SJ == SE) @@ -3364,7 +3393,7 @@ /// This analyzes the alloca to ensure we can reason about it, builds /// the slices of the alloca, and then hands it off to be split and /// rewritten as needed. -bool SROA::runOnAlloca(AllocaInst &AI) { +bool SROA::runOnAlloca(AllocaInst &AI, DIBuilder &DIB) { DEBUG(dbgs() << "SROA alloca: " << AI << "\n"); ++NumAllocasAnalyzed; @@ -3419,7 +3448,7 @@ if (S.begin() == S.end()) return Changed; - Changed |= splitAlloca(AI, S); + Changed |= splitAlloca(AI, S, DIB); DEBUG(dbgs() << " Speculating PHIs\n"); while (!SpeculatablePHIs.empty()) @@ -3596,9 +3625,11 @@ // the list of promotable allocas. SmallPtrSet DeletedAllocas; + DIBuilder DIB(*F.getParent()); + do { while (!Worklist.empty()) { - Changed |= runOnAlloca(*Worklist.pop_back_val()); + Changed |= runOnAlloca(*Worklist.pop_back_val(), DIB); deleteDeadInstructions(DeletedAllocas); // Remove the deleted allocas from various lists so that we don't try to Index: test/DebugInfo/X86/pieces-1.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/pieces-1.ll @@ -0,0 +1,87 @@ +; RUN: opt -sroa -verify -S -asm-verbose -o %t.ll %s +; RUN: cat %t.ll | FileCheck --check-prefix=CHECK-OPT %s +; RUN: llc %t.ll -filetype=obj -o %t.o +; RUN: llvm-dwarfdump -debug-dump=loc %t.o | FileCheck --check-prefix=CHECK-DWARF %s +; +; rdar://problem/15928306 +; +; Test that we can emit debug info for aggregate values that are split +; up across multiple registers by SROA. +; +; // Compile with -O1. +; typedef struct { long int a; int b;} S; +; +; int foo(S s) { +; return s.b; +; } +; +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.9.0" + +%struct.S = type { i64, i32 } + +; Function Attrs: nounwind readnone ssp uwtable +define i32 @foo(i64 %s.coerce0, i32 %s.coerce1) #0 { +entry: + %s = alloca %struct.S, align 8 + %0 = bitcast %struct.S* %s to { i64, i32 }* + %1 = getelementptr { i64, i32 }* %0, i32 0, i32 0 + store i64 %s.coerce0, i64* %1 + %2 = getelementptr { i64, i32 }* %0, i32 0, i32 1 + store i32 %s.coerce1, i32* %2 + call void @llvm.dbg.declare(metadata !{%struct.S* %s}, metadata !16), !dbg !23 + %b = getelementptr inbounds %struct.S* %s, i32 0, i32 1, !dbg !23 + %3 = load i32* %b, align 4, !dbg !21, !tbaa !24 + ret i32 %3, !dbg !24 +} + +; CHECK-OPT: define i32 @foo(i64 %s.coerce0, i32 %s.coerce1) #0 { +; CHECK-OPT: call void @llvm.dbg.value(metadata !{i64 %s.coerce0}, i64 0, metadata ![[PIECE1:.*]]) +; CHECK-OPT: call void @llvm.dbg.value(metadata !{i32 %s.coerce1}, i64 0, metadata ![[PIECE2:.*]]) +; CHECK-OPT: ret i32 %s.coerce1 +; CHECK-OPT: ![[PIECE1]] = {{.*}} i32 3, i32 0, i32 8} ; [ DW_TAG_arg_variable ] [s] [line 3] +; CHECK-OPT: ![[PIECE2]] = {{.*}} i32 3, i32 8, i32 4} ; [ DW_TAG_arg_variable ] [s] [line 3] + +; rdi, piece 0x00000008 +; CHECK-DWARF: Location description: 55 93 08 +; rsi, bit-piece 32 64 +; CHECK-DWARF: Location description: 54 9d 20 40 + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata) #1 + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.value(metadata, i64, metadata) #1 + +attributes #0 = { nounwind ssp uwtable "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!17, !18} +!llvm.ident = !{!19} + +!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.5 ", i1 true, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [pieces.c] [DW_LANG_C99] +!1 = metadata !{metadata !"pieces.c", metadata !""} +!2 = metadata !{} +!3 = metadata !{metadata !4} +!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"foo", metadata !"foo", metadata !"", i32 3, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 true, i32 (i64, i32)* @foo, null, null, metadata !15, i32 3} ; [ DW_TAG_subprogram ] [line 3] [def] [foo] +!5 = metadata !{i32 786473, metadata !1} ; [ DW_TAG_file_type ] [pieces.c] +!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !7, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ] +!7 = metadata !{metadata !8, metadata !9} +!8 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed] +!9 = metadata !{i32 786454, metadata !1, null, metadata !"S", i32 1, i64 0, i64 0, i64 0, i32 0, metadata !10} ; [ DW_TAG_typedef ] [S] [line 1, size 0, align 0, offset 0] [from ] +!10 = metadata !{i32 786451, metadata !1, null, metadata !"", i32 1, i64 128, i64 64, i32 0, i32 0, null, metadata !11, i32 0, null, null, null} ; [ DW_TAG_structure_type ] [line 1, size 128, align 64, offset 0] [def] [from ] +!11 = metadata !{metadata !12, metadata !14} +!12 = metadata !{i32 786445, metadata !1, metadata !10, metadata !"a", i32 1, i64 64, i64 64, i64 0, i32 0, metadata !13} ; [ DW_TAG_member ] [a] [line 1, size 64, align 64, offset 0] [from long int] +!13 = metadata !{i32 786468, null, null, metadata !"long int", i32 0, i64 64, i64 64, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [long int] [line 0, size 64, align 64, offset 0, enc DW_ATE_signed] +!14 = metadata !{i32 786445, metadata !1, metadata !10, metadata !"b", i32 1, i64 32, i64 32, i64 64, i32 0, metadata !8} ; [ DW_TAG_member ] [b] [line 1, size 32, align 32, offset 64] [from int] +!15 = metadata !{metadata !16} +!16 = metadata !{i32 786689, metadata !4, metadata !"s", metadata !5, i32 16777219, metadata !9, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [s] [line 3] +!17 = metadata !{i32 2, metadata !"Dwarf Version", i32 4} +!18 = metadata !{i32 1, metadata !"Debug Info Version", i32 1} +!19 = metadata !{metadata !"clang version 3.5 "} +!20 = metadata !{i32 786689, metadata !4, metadata !"s", metadata !5, i32 16777219, metadata !9, i32 0, i32 0, i32 3, i32 0, i32 8} ; [ DW_TAG_arg_variable ] [s] [line 3] +!21 = metadata !{i32 786689, metadata !4, metadata !"s", metadata !5, i32 16777219, metadata !9, i32 0, i32 0, i32 3, i32 8, i32 4} ; [ DW_TAG_arg_variable ] [s] [line 3] +!22 = metadata !{%struct.S* undef} +!23 = metadata !{i32 3, i32 0, metadata !4, null} +!24 = metadata !{i32 4, i32 0, metadata !4, null} Index: test/DebugInfo/X86/pieces-2.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/pieces-2.ll @@ -0,0 +1,70 @@ +; RUN: llc %s -filetype=obj -o %t.o +; RUN: llvm-dwarfdump -debug-dump=loc %t.o | FileCheck --check-prefix=CHECK-DWARF %s +; +; rdar://problem/15928306 +; +; Test that we can emit debug info for large values that are split +; up across multiple registers by the SelectionDAG type legalizer. +; +; // Compile with -O1 -m32. +; long long foo (long long a, long long b, long long c) +; { +; long long res = c+1; +; if ( a == b ) +; return res; +; return 0; +; } +target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128" +target triple = "i386-apple-macosx10.9.0" + +; eax, piece 0x00000004 +; CHECK-DWARF: Location description: 50 93 04 +; edx, bit-piece 32 32 +; CHECK-DWARF: Location description: 52 9d 20 20 + + +; Function Attrs: nounwind readnone ssp +define i64 @foo(i64 %a, i64 %b, i64 %c) #0 { +entry: + tail call void @llvm.dbg.value(metadata !{i64 %a}, i64 0, metadata !10), !dbg !17 + tail call void @llvm.dbg.value(metadata !{i64 %b}, i64 0, metadata !11), !dbg !17 + tail call void @llvm.dbg.value(metadata !{i64 %c}, i64 0, metadata !12), !dbg !17 + tail call void @llvm.dbg.value(metadata !{i64 %add}, i64 0, metadata !13), !dbg !18 + %cmp = icmp eq i64 %a, %b, !dbg !19 + %add = add nsw i64 %c, 1, !dbg !18 + %retval.0 = select i1 %cmp, i64 %add, i64 0, !dbg !19 + ret i64 %retval.0, !dbg !21 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.value(metadata, i64, metadata) #1 + +attributes #0 = { nounwind readnone ssp } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!14, !15} +!llvm.ident = !{!16} + +!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.5 ", i1 true, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [pieces-2.c] [DW_LANG_C99] +!1 = metadata !{metadata !"pieces-2.c", metadata !""} +!2 = metadata !{} +!3 = metadata !{metadata !4} +!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"foo", metadata !"foo", metadata !"", i32 149, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 true, i64 (i64, i64, i64)* @foo, null, null, metadata !9, i32 150} ; [ DW_TAG_subprogram ] [line 149] [def] [scope 150] [foo] +!5 = metadata !{i32 786473, metadata !1} ; [ DW_TAG_file_type ] [pieces-2.c] +!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !7, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ] +!7 = metadata !{metadata !8, metadata !8, metadata !8, metadata !8} +!8 = metadata !{i32 786468, null, null, metadata !"long long int", i32 0, i64 64, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [long long int] [line 0, size 64, align 32, offset 0, enc DW_ATE_signed] +!9 = metadata !{metadata !10, metadata !11, metadata !12, metadata !13} +!10 = metadata !{i32 786689, metadata !4, metadata !"a", metadata !5, i32 16777365, metadata !8, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [a] [line 149] +!11 = metadata !{i32 786689, metadata !4, metadata !"b", metadata !5, i32 33554581, metadata !8, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [b] [line 149] +!12 = metadata !{i32 786689, metadata !4, metadata !"c", metadata !5, i32 50331797, metadata !8, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [c] [line 149] +!13 = metadata !{i32 786688, metadata !4, metadata !"res", metadata !5, i32 151, metadata !8, i32 0, i32 0} ; [ DW_TAG_auto_variable ] [res] [line 151] +!14 = metadata !{i32 2, metadata !"Dwarf Version", i32 2} +!15 = metadata !{i32 1, metadata !"Debug Info Version", i32 1} +!16 = metadata !{metadata !"clang version 3.5 "} +!17 = metadata !{i32 149, i32 0, metadata !4, null} +!18 = metadata !{i32 151, i32 0, metadata !4, null} +!19 = metadata !{i32 152, i32 0, metadata !20, null} +!20 = metadata !{i32 786443, metadata !1, metadata !4, i32 152, i32 0, i32 0} ; [ DW_TAG_lexical_block ] [pieces-2.c] +!21 = metadata !{i32 155, i32 0, metadata !4, null} Index: test/DebugInfo/X86/pieces-3.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/pieces-3.ll @@ -0,0 +1,73 @@ +; RUN: llc %s -filetype=obj -o %t.o +; RUN: llvm-dwarfdump %t.o | FileCheck --check-prefix=CHECK-DWARF %s +; +; rdar://problem/15928306 +; +; Test that we can emit debug info for large values that are split +; up across multiple registers by the SelectionDAG type legalizer. +; +; // Compile with -O1 -m32. +; long long foo (long long a, long long b, long long c) +; { +; long long res = c+1; +; if ( a == b ) +; return res; +; return res+b; +; } +target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128" +target triple = "i386-apple-macosx10.9.0" + +; ecx, bit-piece 4 4 +; CHECK-DWARF: 51 9d 04 04 + + +; ModuleID = '/Volumes/Data/radar/15928306/iains.c' +target datalayout = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128" +target triple = "i386-apple-macosx10.9.0" + +; Function Attrs: nounwind readnone ssp +define i64 @foo(i64 %a, i64 %b, i64 %c) #0 { +entry: + tail call void @llvm.dbg.value(metadata !{i64 %a}, i64 0, metadata !10), !dbg !17 + tail call void @llvm.dbg.value(metadata !{i64 %b}, i64 0, metadata !11), !dbg !17 + tail call void @llvm.dbg.value(metadata !{i64 %c}, i64 0, metadata !12), !dbg !17 + %add = add nsw i64 %c, 1, !dbg !18 + tail call void @llvm.dbg.value(metadata !{i64 %add}, i64 0, metadata !13), !dbg !18 + %cmp = icmp eq i64 %a, %b, !dbg !19 + %add1 = select i1 %cmp, i64 0, i64 %b, !dbg !19 + %retval.0 = add nsw i64 %add, %add1, !dbg !19 + ret i64 %retval.0, !dbg !21 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.value(metadata, i64, metadata) #1 + +attributes #0 = { nounwind readnone ssp } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!14, !15} +!llvm.ident = !{!16} + +!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.5 ", i1 true, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [pieces-3.c] [DW_LANG_C99] +!1 = metadata !{metadata !"pieces-3.c", metadata !""} +!2 = metadata !{} +!3 = metadata !{metadata !4} +!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"foo", metadata !"foo", metadata !"", i32 149, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 true, i64 (i64, i64, i64)* @foo, null, null, metadata !9, i32 150} ; [ DW_TAG_subprogram ] [line 149] [def] [scope 150] [foo] +!5 = metadata !{i32 786473, metadata !1} ; [ DW_TAG_file_type ] [pieces-3.c] +!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !7, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ] +!7 = metadata !{metadata !8, metadata !8, metadata !8, metadata !8} +!8 = metadata !{i32 786468, null, null, metadata !"long long int", i32 0, i64 64, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [long long int] [line 0, size 64, align 32, offset 0, enc DW_ATE_signed] +!9 = metadata !{metadata !10, metadata !11, metadata !12, metadata !13} +!10 = metadata !{i32 786689, metadata !4, metadata !"a", metadata !5, i32 16777365, metadata !8, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [a] [line 149] +!11 = metadata !{i32 786689, metadata !4, metadata !"b", metadata !5, i32 33554581, metadata !8, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [b] [line 149] +!12 = metadata !{i32 786689, metadata !4, metadata !"c", metadata !5, i32 50331797, metadata !8, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [c] [line 149] +!13 = metadata !{i32 786688, metadata !4, metadata !"res", metadata !5, i32 151, metadata !8, i32 0, i32 0} ; [ DW_TAG_auto_variable ] [res] [line 151] +!14 = metadata !{i32 2, metadata !"Dwarf Version", i32 2} +!15 = metadata !{i32 1, metadata !"Debug Info Version", i32 1} +!16 = metadata !{metadata !"clang version 3.5 "} +!17 = metadata !{i32 149, i32 0, metadata !4, null} +!18 = metadata !{i32 151, i32 0, metadata !4, null} +!19 = metadata !{i32 152, i32 0, metadata !20, null} +!20 = metadata !{i32 786443, metadata !1, metadata !4, i32 152, i32 0, i32 0} ; [ DW_TAG_lexical_block ] [pieces-3.c] +!21 = metadata !{i32 155, i32 0, metadata !4, null}