Index: llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -107,21 +107,29 @@ /// Holds information about all subregisters comprising a register location. struct Register { int DwarfRegNo; - unsigned SubRegSize; - const char *Comment; + uint16_t SubRegisterSizeInBits; + uint16_t SubRegisterOffsetInBits; + enum : char { Full, SuperReg, SubReg } Kind; /// Create a full register, no extra DW_OP_piece operators necessary. - static Register createRegister(int RegNo, const char *Comment) { - return {RegNo, 0, Comment}; + static Register create(int RegNo) { + return {RegNo, 0, 0, Full}; + } + + /// Stencil a subregister out of a superregister. + static Register createSuperReg(int RegNo, uint16_t SizeInBits, + uint16_t OffsetInBits) { + return {RegNo, SizeInBits, OffsetInBits, SuperReg}; } /// Create a subregister that needs a DW_OP_piece operator with SizeInBits. - static Register createSubRegister(int RegNo, unsigned SizeInBits, - const char *Comment) { - return {RegNo, SizeInBits, Comment}; + static Register createSubReg(int RegNo, uint16_t SizeInBits, + uint16_t OffsetInBits) { + return {RegNo, SizeInBits, OffsetInBits, SubReg}; } - bool isSubRegister() const { return SubRegSize; } + /// Return the assembler comment for this register. + const char *getComment() const; }; /// Whether we are currently emitting an entry value operation. @@ -136,8 +144,8 @@ uint64_t OffsetInBits = 0; /// Sometimes we need to add a DW_OP_bit_piece to describe a subregister. - unsigned SubRegisterSizeInBits : 16; - unsigned SubRegisterOffsetInBits : 16; + uint16_t SubRegisterSizeInBits = 0; + uint16_t SubRegisterOffsetInBits = 0; /// The kind of location description being produced. enum { Unknown = 0, Register, Memory, Implicit }; @@ -166,16 +174,12 @@ protected: /// Push a DW_OP_piece / DW_OP_bit_piece for emitting later, if one is needed - /// to represent a subregister. - void setSubRegisterPiece(unsigned SizeInBits, unsigned OffsetInBits) { - assert(SizeInBits < 65536 && OffsetInBits < 65536); + /// to represent a register as a piece of a superregister. + void setSuperRegisterPiece(uint16_t SizeInBits, uint16_t OffsetInBits) { SubRegisterSizeInBits = SizeInBits; SubRegisterOffsetInBits = OffsetInBits; } - /// Add masking operations to stencil out a subregister. - void maskSubRegister(); - /// Output a dwarf operand and an optional assembler comment. virtual void emitOp(uint8_t Op, const char *Comment = nullptr) = 0; @@ -218,7 +222,7 @@ void addReg(int DwarfReg, const char *Comment = nullptr); /// Emit a DW_OP_breg operation. - void addBReg(int DwarfReg, int Offset); + void addBReg(int DwarfReg, int Offset, const char *Comment = nullptr); /// Emit DW_OP_fbreg . void addFBReg(int Offset); @@ -226,10 +230,6 @@ /// Emit a partial DWARF register operation. /// /// \param MachineReg The register number. - /// \param MaxSize If the register must be composed from - /// sub-registers this is an upper bound - /// for how many bits the emitted DW_OP_piece - /// may cover. /// /// If size and offset is zero an operation for the entire register is /// emitted: Some targets do not provide a DWARF register number for every @@ -238,8 +238,7 @@ /// multiple subregisters that alias the register. /// /// \return false if no DWARF register exists for MachineReg. - bool addMachineReg(const TargetRegisterInfo &TRI, unsigned MachineReg, - unsigned MaxSize = ~1U); + bool addMachineReg(const TargetRegisterInfo &TRI, unsigned MachineReg); /// Emit a DW_OP_piece or DW_OP_bit_piece operation for a variable fragment. /// \param OffsetInBits This is an optional offset into the location that @@ -273,8 +272,7 @@ public: DwarfExpression(unsigned DwarfVersion, DwarfCompileUnit &CU) - : CU(CU), SubRegisterSizeInBits(0), SubRegisterOffsetInBits(0), - LocationKind(Unknown), LocationFlags(Unknown), + : CU(CU), LocationKind(Unknown), LocationFlags(Unknown), DwarfVersion(DwarfVersion) {} /// This needs to be called last to commit any pending changes. Index: llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -13,6 +13,7 @@ #include "DwarfExpression.h" #include "DwarfCompileUnit.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/CodeGen/Register.h" @@ -52,13 +53,13 @@ } } -void DwarfExpression::addBReg(int DwarfReg, int Offset) { +void DwarfExpression::addBReg(int DwarfReg, int Offset, const char *Comment) { assert(DwarfReg >= 0 && "invalid negative dwarf register number"); assert(!isRegisterLocation() && "location description already locked down"); if (DwarfReg < 32) { emitOp(dwarf::DW_OP_breg0 + DwarfReg); } else { - emitOp(dwarf::DW_OP_bregx); + emitOp(dwarf::DW_OP_bregx, Comment); emitUnsigned(DwarfReg); } emitSigned(Offset); @@ -97,10 +98,10 @@ } bool DwarfExpression::addMachineReg(const TargetRegisterInfo &TRI, - unsigned MachineReg, unsigned MaxSize) { + unsigned MachineReg) { if (!llvm::Register::isPhysicalRegister(MachineReg)) { if (isFrameRegister(TRI, MachineReg)) { - DwarfRegs.push_back(Register::createRegister(-1, nullptr)); + DwarfRegs.push_back(Register::create(-1)); return true; } return false; @@ -110,7 +111,7 @@ // If this is a valid register number, emit it. if (Reg >= 0) { - DwarfRegs.push_back(Register::createRegister(Reg, nullptr)); + DwarfRegs.push_back(Register::create(Reg)); return true; } @@ -122,9 +123,9 @@ unsigned Idx = TRI.getSubRegIndex(*SR, MachineReg); unsigned Size = TRI.getSubRegIdxSize(Idx); unsigned RegOffset = TRI.getSubRegIdxOffset(Idx); - DwarfRegs.push_back(Register::createRegister(Reg, "super-register")); // Use a DW_OP_bit_piece to describe the sub-register. - setSubRegisterPiece(Size, RegOffset); + DwarfRegs.push_back(Register::createSuperReg(Reg, Size, RegOffset)); + setSuperRegisterPiece(Size, RegOffset); return true; } } @@ -156,16 +157,11 @@ // If this sub-register has a DWARF number and we haven't covered // its range, and its range covers the value, emit a DWARF piece for it. - if (Offset < MaxSize && CurSubReg.test(Coverage)) { - // Emit a piece for any gap in the coverage. + if (CurSubReg.test(Coverage)) { + // Give up if there is a gap in the coverage. if (Offset > CurPos) - DwarfRegs.push_back(Register::createSubRegister( - -1, Offset - CurPos, "no DWARF register encoding")); - if (Offset == 0 && Size >= MaxSize) - DwarfRegs.push_back(Register::createRegister(Reg, "sub-register")); - else - DwarfRegs.push_back(Register::createSubRegister( - Reg, std::min(Size, MaxSize - Offset), "sub-register")); + return false; + DwarfRegs.push_back(Register::createSubReg(Reg, Size, Offset)); } // Mark it as emitted. Coverage.set(Offset, Offset + Size); @@ -176,11 +172,18 @@ return false; // Found a partial or complete DWARF encoding. if (CurPos < RegSize) - DwarfRegs.push_back(Register::createSubRegister( - -1, RegSize - CurPos, "no DWARF register encoding")); + return false; return true; } +const char *DwarfExpression::Register::getComment() const { + switch(Kind) { + case Register::Full: return nullptr; + case Register::SuperReg: return "super-register"; + case Register::SubReg: return "sub-register"; + } +} + void DwarfExpression::addStackValue() { if (DwarfVersion >= 4) emitOp(dwarf::DW_OP_stack_value); @@ -223,8 +226,9 @@ DIExpressionCursor &ExprCursor, unsigned MachineReg, unsigned FragmentOffsetInBits) { - auto Fragment = ExprCursor.getFragmentInfo(); - if (!addMachineReg(TRI, MachineReg, Fragment ? Fragment->SizeInBits : ~1U)) { + auto ClearDwarfRegs = make_scope_exit([this] { DwarfRegs.clear(); }); + + if (!addMachineReg(TRI, MachineReg)) { LocationKind = Unknown; return false; } @@ -234,15 +238,13 @@ if (Op && Op->getOp() != dwarf::DW_OP_LLVM_fragment) HasComplexExpression = true; - // If the register can only be described by a complex expression (i.e., - // multiple subregisters) it doesn't safely compose with another complex - // expression. For example, it is not possible to apply a DW_OP_deref - // operation to multiple DW_OP_pieces. - if (HasComplexExpression && DwarfRegs.size() > 1) { - DwarfRegs.clear(); - LocationKind = Unknown; + // If the register itself can only be described by combining + // multiple subregisters, we cannot use DW_OP_piece, since it + // doesn't safely compose with another complex expression, Since it + // is not possible to apply any DWARF operation to the combined + // DW_OP_pieces. + if (HasComplexExpression && DwarfRegs.size() > 1) return false; - } // Handle simple register locations. If we are supposed to emit // a call site parameter expression and if that expression is just a register @@ -250,19 +252,42 @@ // expression representing a value, rather than a location. if (!isMemoryLocation() && !HasComplexExpression && (!isParameterValue() || isEntryValue())) { + unsigned BitsEmitted = 0; + auto Fragment = ExprCursor.getFragmentInfo(); + unsigned FragmentBits = + Fragment ? Fragment->SizeInBits : std::numeric_limits::max(); for (auto &Reg : DwarfRegs) { - if (Reg.DwarfRegNo >= 0) - addReg(Reg.DwarfRegNo, Reg.Comment); - addOpPiece(Reg.SubRegSize); + switch (Reg.Kind) { + case Register::Full: + case Register::SuperReg: + if (Reg.DwarfRegNo >= 0) + addReg(Reg.DwarfRegNo, Reg.getComment()); + break; + case Register::SubReg: { + // If the last subregister(s) extend beyond the size of the + // fragment, truncate the DW_OP_piece accordingly. This is safe + // because we have a simple expression. + unsigned SubRegBits = Reg.SubRegisterSizeInBits; + if (BitsEmitted + SubRegBits > FragmentBits) + SubRegBits -= (BitsEmitted + SubRegBits) - FragmentBits; + BitsEmitted += SubRegBits; + if (SubRegBits == 0) + break; + if (Reg.DwarfRegNo >= 0) + addReg(Reg.DwarfRegNo, Reg.getComment()); + if (SubRegBits < FragmentBits) + addOpPiece(SubRegBits); + break; + } + } } - + if (isEntryValue()) finalizeEntryValue(); if (isEntryValue() && !isParameterValue() && DwarfVersion >= 4) emitOp(dwarf::DW_OP_stack_value); - DwarfRegs.clear(); return true; } @@ -271,16 +296,21 @@ if (any_of(ExprCursor, [](DIExpression::ExprOperand Op) -> bool { return Op.getOp() == dwarf::DW_OP_stack_value; })) { - DwarfRegs.clear(); LocationKind = Unknown; return false; } - assert(DwarfRegs.size() == 1); - auto Reg = DwarfRegs[0]; + if (DwarfRegs.size() != 1) { + // While this could happen legitimately, it is more likely to + // indicate a bug. + assert(isMemoryLocation() && "pointer spawns multiple registers"); + return false; + } + + auto Reg = DwarfRegs.front(); bool FBReg = isFrameRegister(TRI, MachineReg); int SignedOffset = 0; - assert(!Reg.isSubRegister() && "full register expected"); + assert(Reg.Kind != Register::SubReg && "full register expected"); // Pattern-match combinations for which more efficient representations exist. // [Reg, DW_OP_plus_uconst, Offset] --> [DW_OP_breg, Offset]. @@ -304,7 +334,7 @@ SignedOffset = Offset; ExprCursor.consume(2); } else if (N && N->getOp() == dwarf::DW_OP_minus && - !SubRegisterSizeInBits && Offset <= IntMax + 1) { + !Reg.SubRegisterSizeInBits && Offset <= IntMax + 1) { SignedOffset = -static_cast(Offset); ExprCursor.consume(2); } @@ -314,7 +344,6 @@ addFBReg(SignedOffset); else addBReg(Reg.DwarfRegNo, SignedOffset); - DwarfRegs.clear(); return true; } @@ -381,11 +410,16 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor, unsigned FragmentOffsetInBits) { + auto N = ExprCursor.peek(); + // If we need to mask out a subregister, do it now, unless the next // operation would emit an OpPiece anyway. - auto N = ExprCursor.peek(); - if (SubRegisterSizeInBits && N && (N->getOp() != dwarf::DW_OP_LLVM_fragment)) - maskSubRegister(); + if (SubRegisterSizeInBits && N && (N->getOp() != dwarf::DW_OP_LLVM_fragment)) { + if (SubRegisterOffsetInBits > 0) + addShr(SubRegisterOffsetInBits); + uint64_t Mask = (1ULL << (uint64_t)SubRegisterSizeInBits) - 1ULL; + addAnd(Mask); + } Optional PrevConvertOp = None; @@ -427,7 +461,7 @@ // Emit the DW_OP_piece. addOpPiece(SizeInBits, SubRegisterOffsetInBits); - setSubRegisterPiece(0, 0); + setSuperRegisterPiece(0, 0); // Reset the location description kind. LocationKind = Unknown; return; @@ -528,15 +562,6 @@ addStackValue(); } -/// add masking operations to stencil out a subregister. -void DwarfExpression::maskSubRegister() { - assert(SubRegisterSizeInBits && "no subregister was registered"); - if (SubRegisterOffsetInBits > 0) - addShr(SubRegisterOffsetInBits); - uint64_t Mask = (1ULL << (uint64_t)SubRegisterSizeInBits) - 1ULL; - addAnd(Mask); -} - void DwarfExpression::finalize() { assert(DwarfRegs.size() == 0 && "dwarf registers not emitted"); // Emit any outstanding DW_OP_piece operations to mask out subregisters.