diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp | 740 |
1 files changed, 740 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp new file mode 100644 index 000000000000..7623b7fb7c5d --- /dev/null +++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -0,0 +1,740 @@ +//===- llvm/CodeGen/DwarfExpression.cpp - Dwarf Debug Framework -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing dwarf debug info into asm files. +// +//===----------------------------------------------------------------------===// + +#include "DwarfExpression.h" +#include "DwarfCompileUnit.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/SmallBitVector.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/CodeGen/Register.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/Support/ErrorHandling.h" +#include <algorithm> + +using namespace llvm; + +#define DEBUG_TYPE "dwarfdebug" + +void DwarfExpression::emitConstu(uint64_t Value) { + if (Value < 32) + emitOp(dwarf::DW_OP_lit0 + Value); + else if (Value == std::numeric_limits<uint64_t>::max()) { + // Only do this for 64-bit values as the DWARF expression stack uses + // target-address-size values. + emitOp(dwarf::DW_OP_lit0); + emitOp(dwarf::DW_OP_not); + } else { + emitOp(dwarf::DW_OP_constu); + emitUnsigned(Value); + } +} + +void DwarfExpression::addReg(int DwarfReg, const char *Comment) { + assert(DwarfReg >= 0 && "invalid negative dwarf register number"); + assert((isUnknownLocation() || isRegisterLocation()) && + "location description already locked down"); + LocationKind = Register; + if (DwarfReg < 32) { + emitOp(dwarf::DW_OP_reg0 + DwarfReg, Comment); + } else { + emitOp(dwarf::DW_OP_regx, Comment); + emitUnsigned(DwarfReg); + } +} + +void DwarfExpression::addBReg(int DwarfReg, int Offset) { + 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); + emitUnsigned(DwarfReg); + } + emitSigned(Offset); +} + +void DwarfExpression::addFBReg(int Offset) { + emitOp(dwarf::DW_OP_fbreg); + emitSigned(Offset); +} + +void DwarfExpression::addOpPiece(unsigned SizeInBits, unsigned OffsetInBits) { + if (!SizeInBits) + return; + + const unsigned SizeOfByte = 8; + if (OffsetInBits > 0 || SizeInBits % SizeOfByte) { + emitOp(dwarf::DW_OP_bit_piece); + emitUnsigned(SizeInBits); + emitUnsigned(OffsetInBits); + } else { + emitOp(dwarf::DW_OP_piece); + unsigned ByteSize = SizeInBits / SizeOfByte; + emitUnsigned(ByteSize); + } + this->OffsetInBits += SizeInBits; +} + +void DwarfExpression::addShr(unsigned ShiftBy) { + emitConstu(ShiftBy); + emitOp(dwarf::DW_OP_shr); +} + +void DwarfExpression::addAnd(unsigned Mask) { + emitConstu(Mask); + emitOp(dwarf::DW_OP_and); +} + +bool DwarfExpression::addMachineReg(const TargetRegisterInfo &TRI, + llvm::Register MachineReg, + unsigned MaxSize) { + if (!MachineReg.isPhysical()) { + if (isFrameRegister(TRI, MachineReg)) { + DwarfRegs.push_back(Register::createRegister(-1, nullptr)); + return true; + } + return false; + } + + int Reg = TRI.getDwarfRegNum(MachineReg, false); + + // If this is a valid register number, emit it. + if (Reg >= 0) { + DwarfRegs.push_back(Register::createRegister(Reg, nullptr)); + return true; + } + + // Walk up the super-register chain until we find a valid number. + // For example, EAX on x86_64 is a 32-bit fragment of RAX with offset 0. + for (MCPhysReg SR : TRI.superregs(MachineReg)) { + Reg = TRI.getDwarfRegNum(SR, false); + if (Reg >= 0) { + 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); + return true; + } + } + + // Otherwise, attempt to find a covering set of sub-register numbers. + // For example, Q0 on ARM is a composition of D0+D1. + unsigned CurPos = 0; + // The size of the register in bits. + const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(MachineReg); + unsigned RegSize = TRI.getRegSizeInBits(*RC); + // Keep track of the bits in the register we already emitted, so we + // can avoid emitting redundant aliasing subregs. Because this is + // just doing a greedy scan of all subregisters, it is possible that + // this doesn't find a combination of subregisters that fully cover + // the register (even though one may exist). + SmallBitVector Coverage(RegSize, false); + for (MCPhysReg SR : TRI.subregs(MachineReg)) { + unsigned Idx = TRI.getSubRegIndex(MachineReg, SR); + unsigned Size = TRI.getSubRegIdxSize(Idx); + unsigned Offset = TRI.getSubRegIdxOffset(Idx); + Reg = TRI.getDwarfRegNum(SR, false); + if (Reg < 0) + continue; + + // Used to build the intersection between the bits we already + // emitted and the bits covered by this subregister. + SmallBitVector CurSubReg(RegSize, false); + CurSubReg.set(Offset, Offset + Size); + + // 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 (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<unsigned>(Size, MaxSize - Offset), "sub-register")); + } + // Mark it as emitted. + Coverage.set(Offset, Offset + Size); + CurPos = Offset + Size; + } + // Failed to find any DWARF encoding. + if (CurPos == 0) + 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 true; +} + +void DwarfExpression::addStackValue() { + if (DwarfVersion >= 4) + emitOp(dwarf::DW_OP_stack_value); +} + +void DwarfExpression::addSignedConstant(int64_t Value) { + assert(isImplicitLocation() || isUnknownLocation()); + LocationKind = Implicit; + emitOp(dwarf::DW_OP_consts); + emitSigned(Value); +} + +void DwarfExpression::addUnsignedConstant(uint64_t Value) { + assert(isImplicitLocation() || isUnknownLocation()); + LocationKind = Implicit; + emitConstu(Value); +} + +void DwarfExpression::addUnsignedConstant(const APInt &Value) { + assert(isImplicitLocation() || isUnknownLocation()); + LocationKind = Implicit; + + unsigned Size = Value.getBitWidth(); + const uint64_t *Data = Value.getRawData(); + + // Chop it up into 64-bit pieces, because that's the maximum that + // addUnsignedConstant takes. + unsigned Offset = 0; + while (Offset < Size) { + addUnsignedConstant(*Data++); + if (Offset == 0 && Size <= 64) + break; + addStackValue(); + addOpPiece(std::min(Size - Offset, 64u), Offset); + Offset += 64; + } +} + +void DwarfExpression::addConstantFP(const APFloat &APF, const AsmPrinter &AP) { + assert(isImplicitLocation() || isUnknownLocation()); + APInt API = APF.bitcastToAPInt(); + int NumBytes = API.getBitWidth() / 8; + if (NumBytes == 4 /*float*/ || NumBytes == 8 /*double*/) { + // FIXME: Add support for `long double`. + emitOp(dwarf::DW_OP_implicit_value); + emitUnsigned(NumBytes /*Size of the block in bytes*/); + + // The loop below is emitting the value starting at least significant byte, + // so we need to perform a byte-swap to get the byte order correct in case + // of a big-endian target. + if (AP.getDataLayout().isBigEndian()) + API = API.byteSwap(); + + for (int i = 0; i < NumBytes; ++i) { + emitData1(API.getZExtValue() & 0xFF); + API = API.lshr(8); + } + + return; + } + LLVM_DEBUG( + dbgs() << "Skipped DW_OP_implicit_value creation for ConstantFP of size: " + << API.getBitWidth() << " bits\n"); +} + +bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI, + DIExpressionCursor &ExprCursor, + llvm::Register MachineReg, + unsigned FragmentOffsetInBits) { + auto Fragment = ExprCursor.getFragmentInfo(); + if (!addMachineReg(TRI, MachineReg, Fragment ? Fragment->SizeInBits : ~1U)) { + LocationKind = Unknown; + return false; + } + + bool HasComplexExpression = false; + auto Op = ExprCursor.peek(); + 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, since composite location descriptions + // do not push anything on the DWARF stack. + // + // DW_OP_entry_value operations can only hold a DWARF expression or a + // register location description, so we can't emit a single entry value + // covering a composite location description. In the future we may want to + // emit entry value operations for each register location in the composite + // location, but until that is supported do not emit anything. + if ((HasComplexExpression || IsEmittingEntryValue) && DwarfRegs.size() > 1) { + if (IsEmittingEntryValue) + cancelEntryValue(); + DwarfRegs.clear(); + LocationKind = Unknown; + 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 + // location, emit it with addBReg and offset 0, because we should emit a DWARF + // expression representing a value, rather than a location. + if ((!isParameterValue() && !isMemoryLocation() && !HasComplexExpression) || + isEntryValue()) { + auto FragmentInfo = ExprCursor.getFragmentInfo(); + unsigned RegSize = 0; + for (auto &Reg : DwarfRegs) { + RegSize += Reg.SubRegSize; + if (Reg.DwarfRegNo >= 0) + addReg(Reg.DwarfRegNo, Reg.Comment); + if (FragmentInfo) + if (RegSize > FragmentInfo->SizeInBits) + // If the register is larger than the current fragment stop + // once the fragment is covered. + break; + addOpPiece(Reg.SubRegSize); + } + + if (isEntryValue()) { + finalizeEntryValue(); + + if (!isIndirect() && !isParameterValue() && !HasComplexExpression && + DwarfVersion >= 4) + emitOp(dwarf::DW_OP_stack_value); + } + + DwarfRegs.clear(); + // If we need to mask out a subregister, do it now, unless the next + // operation would emit an OpPiece anyway. + auto NextOp = ExprCursor.peek(); + if (SubRegisterSizeInBits && NextOp && + (NextOp->getOp() != dwarf::DW_OP_LLVM_fragment)) + maskSubRegister(); + return true; + } + + // Don't emit locations that cannot be expressed without DW_OP_stack_value. + if (DwarfVersion < 4) + if (any_of(ExprCursor, [](DIExpression::ExprOperand Op) -> bool { + return Op.getOp() == dwarf::DW_OP_stack_value; + })) { + DwarfRegs.clear(); + LocationKind = Unknown; + return false; + } + + // TODO: We should not give up here but the following code needs to be changed + // to deal with multiple (sub)registers first. + if (DwarfRegs.size() > 1) { + LLVM_DEBUG(dbgs() << "TODO: giving up on debug information due to " + "multi-register usage.\n"); + DwarfRegs.clear(); + LocationKind = Unknown; + return false; + } + + auto Reg = DwarfRegs[0]; + bool FBReg = isFrameRegister(TRI, MachineReg); + int SignedOffset = 0; + assert(!Reg.isSubRegister() && "full register expected"); + + // Pattern-match combinations for which more efficient representations exist. + // [Reg, DW_OP_plus_uconst, Offset] --> [DW_OP_breg, Offset]. + if (Op && (Op->getOp() == dwarf::DW_OP_plus_uconst)) { + uint64_t Offset = Op->getArg(0); + uint64_t IntMax = static_cast<uint64_t>(std::numeric_limits<int>::max()); + if (Offset <= IntMax) { + SignedOffset = Offset; + ExprCursor.take(); + } + } + + // [Reg, DW_OP_constu, Offset, DW_OP_plus] --> [DW_OP_breg, Offset] + // [Reg, DW_OP_constu, Offset, DW_OP_minus] --> [DW_OP_breg,-Offset] + // If Reg is a subregister we need to mask it out before subtracting. + if (Op && Op->getOp() == dwarf::DW_OP_constu) { + uint64_t Offset = Op->getArg(0); + uint64_t IntMax = static_cast<uint64_t>(std::numeric_limits<int>::max()); + auto N = ExprCursor.peekNext(); + if (N && N->getOp() == dwarf::DW_OP_plus && Offset <= IntMax) { + SignedOffset = Offset; + ExprCursor.consume(2); + } else if (N && N->getOp() == dwarf::DW_OP_minus && + !SubRegisterSizeInBits && Offset <= IntMax + 1) { + SignedOffset = -static_cast<int64_t>(Offset); + ExprCursor.consume(2); + } + } + + if (FBReg) + addFBReg(SignedOffset); + else + addBReg(Reg.DwarfRegNo, SignedOffset); + DwarfRegs.clear(); + + // If we need to mask out a subregister, do it now, unless the next + // operation would emit an OpPiece anyway. + auto NextOp = ExprCursor.peek(); + if (SubRegisterSizeInBits && NextOp && + (NextOp->getOp() != dwarf::DW_OP_LLVM_fragment)) + maskSubRegister(); + + return true; +} + +void DwarfExpression::setEntryValueFlags(const MachineLocation &Loc) { + LocationFlags |= EntryValue; + if (Loc.isIndirect()) + LocationFlags |= Indirect; +} + +void DwarfExpression::setLocation(const MachineLocation &Loc, + const DIExpression *DIExpr) { + if (Loc.isIndirect()) + setMemoryLocationKind(); + + if (DIExpr->isEntryValue()) + setEntryValueFlags(Loc); +} + +void DwarfExpression::beginEntryValueExpression( + DIExpressionCursor &ExprCursor) { + auto Op = ExprCursor.take(); + (void)Op; + assert(Op && Op->getOp() == dwarf::DW_OP_LLVM_entry_value); + assert(!IsEmittingEntryValue && "Already emitting entry value?"); + assert(Op->getArg(0) == 1 && + "Can currently only emit entry values covering a single operation"); + + SavedLocationKind = LocationKind; + LocationKind = Register; + IsEmittingEntryValue = true; + enableTemporaryBuffer(); +} + +void DwarfExpression::finalizeEntryValue() { + assert(IsEmittingEntryValue && "Entry value not open?"); + disableTemporaryBuffer(); + + emitOp(CU.getDwarf5OrGNULocationAtom(dwarf::DW_OP_entry_value)); + + // Emit the entry value's size operand. + unsigned Size = getTemporaryBufferSize(); + emitUnsigned(Size); + + // Emit the entry value's DWARF block operand. + commitTemporaryBuffer(); + + LocationFlags &= ~EntryValue; + LocationKind = SavedLocationKind; + IsEmittingEntryValue = false; +} + +void DwarfExpression::cancelEntryValue() { + assert(IsEmittingEntryValue && "Entry value not open?"); + disableTemporaryBuffer(); + + // The temporary buffer can't be emptied, so for now just assert that nothing + // has been emitted to it. + assert(getTemporaryBufferSize() == 0 && + "Began emitting entry value block before cancelling entry value"); + + LocationKind = SavedLocationKind; + IsEmittingEntryValue = false; +} + +unsigned DwarfExpression::getOrCreateBaseType(unsigned BitSize, + dwarf::TypeKind Encoding) { + // Reuse the base_type if we already have one in this CU otherwise we + // create a new one. + unsigned I = 0, E = CU.ExprRefedBaseTypes.size(); + for (; I != E; ++I) + if (CU.ExprRefedBaseTypes[I].BitSize == BitSize && + CU.ExprRefedBaseTypes[I].Encoding == Encoding) + break; + + if (I == E) + CU.ExprRefedBaseTypes.emplace_back(BitSize, Encoding); + return I; +} + +/// Assuming a well-formed expression, match "DW_OP_deref* +/// DW_OP_LLVM_fragment?". +static bool isMemoryLocation(DIExpressionCursor ExprCursor) { + while (ExprCursor) { + auto Op = ExprCursor.take(); + switch (Op->getOp()) { + case dwarf::DW_OP_deref: + case dwarf::DW_OP_LLVM_fragment: + break; + default: + return false; + } + } + return true; +} + +void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor) { + addExpression(std::move(ExprCursor), + [](unsigned Idx, DIExpressionCursor &Cursor) -> bool { + llvm_unreachable("unhandled opcode found in expression"); + }); +} + +bool DwarfExpression::addExpression( + DIExpressionCursor &&ExprCursor, + llvm::function_ref<bool(unsigned, DIExpressionCursor &)> InsertArg) { + // Entry values can currently only cover the initial register location, + // and not any other parts of the following DWARF expression. + assert(!IsEmittingEntryValue && "Can't emit entry value around expression"); + + std::optional<DIExpression::ExprOperand> PrevConvertOp; + + while (ExprCursor) { + auto Op = ExprCursor.take(); + uint64_t OpNum = Op->getOp(); + + if (OpNum >= dwarf::DW_OP_reg0 && OpNum <= dwarf::DW_OP_reg31) { + emitOp(OpNum); + continue; + } else if (OpNum >= dwarf::DW_OP_breg0 && OpNum <= dwarf::DW_OP_breg31) { + addBReg(OpNum - dwarf::DW_OP_breg0, Op->getArg(0)); + continue; + } + + switch (OpNum) { + case dwarf::DW_OP_LLVM_arg: + if (!InsertArg(Op->getArg(0), ExprCursor)) { + LocationKind = Unknown; + return false; + } + break; + case dwarf::DW_OP_LLVM_fragment: { + unsigned SizeInBits = Op->getArg(1); + unsigned FragmentOffset = Op->getArg(0); + // The fragment offset must have already been adjusted by emitting an + // empty DW_OP_piece / DW_OP_bit_piece before we emitted the base + // location. + assert(OffsetInBits >= FragmentOffset && "fragment offset not added?"); + assert(SizeInBits >= OffsetInBits - FragmentOffset && "size underflow"); + + // If addMachineReg already emitted DW_OP_piece operations to represent + // a super-register by splicing together sub-registers, subtract the size + // of the pieces that was already emitted. + SizeInBits -= OffsetInBits - FragmentOffset; + + // If addMachineReg requested a DW_OP_bit_piece to stencil out a + // sub-register that is smaller than the current fragment's size, use it. + if (SubRegisterSizeInBits) + SizeInBits = std::min<unsigned>(SizeInBits, SubRegisterSizeInBits); + + // Emit a DW_OP_stack_value for implicit location descriptions. + if (isImplicitLocation()) + addStackValue(); + + // Emit the DW_OP_piece. + addOpPiece(SizeInBits, SubRegisterOffsetInBits); + setSubRegisterPiece(0, 0); + // Reset the location description kind. + LocationKind = Unknown; + return true; + } + case dwarf::DW_OP_plus_uconst: + assert(!isRegisterLocation()); + emitOp(dwarf::DW_OP_plus_uconst); + emitUnsigned(Op->getArg(0)); + break; + case dwarf::DW_OP_plus: + case dwarf::DW_OP_minus: + case dwarf::DW_OP_mul: + case dwarf::DW_OP_div: + case dwarf::DW_OP_mod: + case dwarf::DW_OP_or: + case dwarf::DW_OP_and: + case dwarf::DW_OP_xor: + case dwarf::DW_OP_shl: + case dwarf::DW_OP_shr: + case dwarf::DW_OP_shra: + case dwarf::DW_OP_lit0: + case dwarf::DW_OP_not: + case dwarf::DW_OP_dup: + case dwarf::DW_OP_push_object_address: + case dwarf::DW_OP_over: + case dwarf::DW_OP_eq: + case dwarf::DW_OP_ne: + case dwarf::DW_OP_gt: + case dwarf::DW_OP_ge: + case dwarf::DW_OP_lt: + case dwarf::DW_OP_le: + emitOp(OpNum); + break; + case dwarf::DW_OP_deref: + assert(!isRegisterLocation()); + if (!isMemoryLocation() && ::isMemoryLocation(ExprCursor)) + // Turning this into a memory location description makes the deref + // implicit. + LocationKind = Memory; + else + emitOp(dwarf::DW_OP_deref); + break; + case dwarf::DW_OP_constu: + assert(!isRegisterLocation()); + emitConstu(Op->getArg(0)); + break; + case dwarf::DW_OP_consts: + assert(!isRegisterLocation()); + emitOp(dwarf::DW_OP_consts); + emitSigned(Op->getArg(0)); + break; + case dwarf::DW_OP_LLVM_convert: { + unsigned BitSize = Op->getArg(0); + dwarf::TypeKind Encoding = static_cast<dwarf::TypeKind>(Op->getArg(1)); + if (DwarfVersion >= 5 && CU.getDwarfDebug().useOpConvert()) { + emitOp(dwarf::DW_OP_convert); + // If targeting a location-list; simply emit the index into the raw + // byte stream as ULEB128, DwarfDebug::emitDebugLocEntry has been + // fitted with means to extract it later. + // If targeting a inlined DW_AT_location; insert a DIEBaseTypeRef + // (containing the index and a resolve mechanism during emit) into the + // DIE value list. + emitBaseTypeRef(getOrCreateBaseType(BitSize, Encoding)); + } else { + if (PrevConvertOp && PrevConvertOp->getArg(0) < BitSize) { + if (Encoding == dwarf::DW_ATE_signed) + emitLegacySExt(PrevConvertOp->getArg(0)); + else if (Encoding == dwarf::DW_ATE_unsigned) + emitLegacyZExt(PrevConvertOp->getArg(0)); + PrevConvertOp = std::nullopt; + } else { + PrevConvertOp = Op; + } + } + break; + } + case dwarf::DW_OP_stack_value: + LocationKind = Implicit; + break; + case dwarf::DW_OP_swap: + assert(!isRegisterLocation()); + emitOp(dwarf::DW_OP_swap); + break; + case dwarf::DW_OP_xderef: + assert(!isRegisterLocation()); + emitOp(dwarf::DW_OP_xderef); + break; + case dwarf::DW_OP_deref_size: + emitOp(dwarf::DW_OP_deref_size); + emitData1(Op->getArg(0)); + break; + case dwarf::DW_OP_LLVM_tag_offset: + TagOffset = Op->getArg(0); + break; + case dwarf::DW_OP_regx: + emitOp(dwarf::DW_OP_regx); + emitUnsigned(Op->getArg(0)); + break; + case dwarf::DW_OP_bregx: + emitOp(dwarf::DW_OP_bregx); + emitUnsigned(Op->getArg(0)); + emitSigned(Op->getArg(1)); + break; + default: + llvm_unreachable("unhandled opcode found in expression"); + } + } + + if (isImplicitLocation() && !isParameterValue()) + // Turn this into an implicit location description. + addStackValue(); + + return true; +} + +/// 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. + if (SubRegisterSizeInBits == 0) + return; + // Don't emit a DW_OP_piece for a subregister at offset 0. + if (SubRegisterOffsetInBits == 0) + return; + addOpPiece(SubRegisterSizeInBits, SubRegisterOffsetInBits); +} + +void DwarfExpression::addFragmentOffset(const DIExpression *Expr) { + if (!Expr || !Expr->isFragment()) + return; + + uint64_t FragmentOffset = Expr->getFragmentInfo()->OffsetInBits; + assert(FragmentOffset >= OffsetInBits && + "overlapping or duplicate fragments"); + if (FragmentOffset > OffsetInBits) + addOpPiece(FragmentOffset - OffsetInBits); + OffsetInBits = FragmentOffset; +} + +void DwarfExpression::emitLegacySExt(unsigned FromBits) { + // (((X >> (FromBits - 1)) * (~0)) << FromBits) | X + emitOp(dwarf::DW_OP_dup); + emitOp(dwarf::DW_OP_constu); + emitUnsigned(FromBits - 1); + emitOp(dwarf::DW_OP_shr); + emitOp(dwarf::DW_OP_lit0); + emitOp(dwarf::DW_OP_not); + emitOp(dwarf::DW_OP_mul); + emitOp(dwarf::DW_OP_constu); + emitUnsigned(FromBits); + emitOp(dwarf::DW_OP_shl); + emitOp(dwarf::DW_OP_or); +} + +void DwarfExpression::emitLegacyZExt(unsigned FromBits) { + // Heuristic to decide the most efficient encoding. + // A ULEB can encode 7 1-bits per byte. + if (FromBits / 7 < 1+1+1+1+1) { + // (X & (1 << FromBits - 1)) + emitOp(dwarf::DW_OP_constu); + emitUnsigned((1ULL << FromBits) - 1); + } else { + // Note that the DWARF 4 stack consists of pointer-sized elements, + // so technically it doesn't make sense to shift left more than 64 + // bits. We leave that for the consumer to decide though. LLDB for + // example uses APInt for the stack elements and can still deal + // with this. + emitOp(dwarf::DW_OP_lit1); + emitOp(dwarf::DW_OP_constu); + emitUnsigned(FromBits); + emitOp(dwarf::DW_OP_shl); + emitOp(dwarf::DW_OP_lit1); + emitOp(dwarf::DW_OP_minus); + } + emitOp(dwarf::DW_OP_and); +} + +void DwarfExpression::addWasmLocation(unsigned Index, uint64_t Offset) { + emitOp(dwarf::DW_OP_WASM_location); + emitUnsigned(Index == 4/*TI_LOCAL_INDIRECT*/ ? 0/*TI_LOCAL*/ : Index); + emitUnsigned(Offset); + if (Index == 4 /*TI_LOCAL_INDIRECT*/) { + assert(LocationKind == Unknown); + LocationKind = Memory; + } else { + assert(LocationKind == Implicit || LocationKind == Unknown); + LocationKind = Implicit; + } +} |