brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.9 KiB · c4929ae Raw
381 lines · c
1//===- llvm/CodeGen/DwarfExpression.h - Dwarf Compile Unit ------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains support for writing dwarf compile unit.10//11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DWARFEXPRESSION_H14#define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFEXPRESSION_H15 16#include "ByteStreamer.h"17#include "llvm/ADT/ArrayRef.h"18#include "llvm/ADT/SmallVector.h"19#include "llvm/IR/DebugInfoMetadata.h"20#include <cassert>21#include <cstdint>22#include <optional>23 24namespace llvm {25 26class AsmPrinter;27class APInt;28class DwarfCompileUnit;29class DIELoc;30class TargetRegisterInfo;31class MachineLocation;32 33/// Base class containing the logic for constructing DWARF expressions34/// independently of whether they are emitted into a DIE or into a .debug_loc35/// entry.36///37/// Some DWARF operations, e.g. DW_OP_entry_value, need to calculate the size38/// of a succeeding DWARF block before the latter is emitted to the output.39/// To handle such cases, data can conditionally be emitted to a temporary40/// buffer, which can later on be committed to the main output. The size of the41/// temporary buffer is queryable, allowing for the size of the data to be42/// emitted before the data is committed.43class DwarfExpression {44protected:45  /// Holds information about all subregisters comprising a register location.46  struct Register {47    int64_t DwarfRegNo;48    unsigned SubRegSize;49    const char *Comment;50 51    /// Create a full register, no extra DW_OP_piece operators necessary.52    static Register createRegister(int64_t RegNo, const char *Comment) {53      return {RegNo, 0, Comment};54    }55 56    /// Create a subregister that needs a DW_OP_piece operator with SizeInBits.57    static Register createSubRegister(int64_t RegNo, unsigned SizeInBits,58                                      const char *Comment) {59      return {RegNo, SizeInBits, Comment};60    }61 62    bool isSubRegister() const { return SubRegSize; }63  };64 65  /// Whether we are currently emitting an entry value operation.66  bool IsEmittingEntryValue = false;67 68  DwarfCompileUnit &CU;69 70  /// The register location, if any.71  SmallVector<Register, 2> DwarfRegs;72 73  /// Current Fragment Offset in Bits.74  uint64_t OffsetInBits = 0;75 76  /// Sometimes we need to add a DW_OP_bit_piece to describe a subregister.77  unsigned SubRegisterSizeInBits : 16;78  unsigned SubRegisterOffsetInBits : 16;79 80  /// The kind of location description being produced.81  enum { Unknown = 0, Register, Memory, Implicit };82 83  /// Additional location flags which may be combined with any location kind.84  /// Currently, entry values are not supported for the Memory location kind.85  enum { EntryValue = 1 << 0, Indirect = 1 << 1, CallSiteParamValue = 1 << 2 };86 87  unsigned LocationKind : 3;88  unsigned SavedLocationKind : 3;89  unsigned LocationFlags : 3;90  unsigned DwarfVersion : 4;91 92public:93  /// Set the location (\p Loc) and \ref DIExpression (\p DIExpr) to describe.94  void setLocation(const MachineLocation &Loc, const DIExpression *DIExpr);95 96  bool isUnknownLocation() const { return LocationKind == Unknown; }97 98  bool isMemoryLocation() const { return LocationKind == Memory; }99 100  bool isRegisterLocation() const { return LocationKind == Register; }101 102  bool isImplicitLocation() const { return LocationKind == Implicit; }103 104  bool isEntryValue() const { return LocationFlags & EntryValue; }105 106  bool isIndirect() const { return LocationFlags & Indirect; }107 108  bool isParameterValue() { return LocationFlags & CallSiteParamValue; }109 110  std::optional<uint8_t> TagOffset;111 112protected:113  /// Push a DW_OP_piece / DW_OP_bit_piece for emitting later, if one is needed114  /// to represent a subregister.115  void setSubRegisterPiece(unsigned SizeInBits, unsigned OffsetInBits) {116    assert(SizeInBits < 65536 && OffsetInBits < 65536);117    SubRegisterSizeInBits = SizeInBits;118    SubRegisterOffsetInBits = OffsetInBits;119  }120 121  /// Add masking operations to stencil out a subregister.122  void maskSubRegister();123 124  /// Output a dwarf operand and an optional assembler comment.125  virtual void emitOp(uint8_t Op, const char *Comment = nullptr) = 0;126 127  /// Emit a raw signed value.128  virtual void emitSigned(int64_t Value) = 0;129 130  /// Emit a raw unsigned value.131  virtual void emitUnsigned(uint64_t Value) = 0;132 133  virtual void emitData1(uint8_t Value) = 0;134 135  virtual void emitBaseTypeRef(uint64_t Idx) = 0;136 137  /// Start emitting data to the temporary buffer. The data stored in the138  /// temporary buffer can be committed to the main output using139  /// commitTemporaryBuffer().140  virtual void enableTemporaryBuffer() = 0;141 142  /// Disable emission to the temporary buffer. This does not commit data143  /// in the temporary buffer to the main output.144  virtual void disableTemporaryBuffer() = 0;145 146  /// Return the emitted size, in number of bytes, for the data stored in the147  /// temporary buffer.148  virtual unsigned getTemporaryBufferSize() = 0;149 150  /// Commit the data stored in the temporary buffer to the main output.151  virtual void commitTemporaryBuffer() = 0;152 153  /// Emit a normalized unsigned constant.154  void emitConstu(uint64_t Value);155 156  /// Return whether the given machine register is the frame register in the157  /// current function.158  virtual bool isFrameRegister(const TargetRegisterInfo &TRI,159                               llvm::Register MachineReg) = 0;160 161  /// Emit a DW_OP_reg operation. Note that this is only legal inside a DWARF162  /// register location description.163  void addReg(int64_t DwarfReg, const char *Comment = nullptr);164 165  /// Emit a DW_OP_breg operation.166  void addBReg(int64_t DwarfReg, int64_t Offset);167 168  /// Emit DW_OP_fbreg <Offset>.169  void addFBReg(int64_t Offset);170 171  /// Emit a partial DWARF register operation.172  ///173  /// \param MachineReg           The register number.174  /// \param MaxSize              If the register must be composed from175  ///                             sub-registers this is an upper bound176  ///                             for how many bits the emitted DW_OP_piece177  ///                             may cover.178  ///179  /// If size and offset is zero an operation for the entire register is180  /// emitted: Some targets do not provide a DWARF register number for every181  /// register.  If this is the case, this function will attempt to emit a DWARF182  /// register by emitting a fragment of a super-register or by piecing together183  /// multiple subregisters that alias the register.184  ///185  /// \return false if no DWARF register exists for MachineReg.186  bool addMachineReg(const TargetRegisterInfo &TRI, llvm::Register MachineReg,187                     unsigned MaxSize = ~1U);188 189  /// Emit a DW_OP_piece or DW_OP_bit_piece operation for a variable fragment.190  /// \param OffsetInBits    This is an optional offset into the location that191  /// is at the top of the DWARF stack.192  void addOpPiece(unsigned SizeInBits, unsigned OffsetInBits = 0);193 194  /// Emit a shift-right dwarf operation.195  void addShr(unsigned ShiftBy);196 197  /// Emit a bitwise and dwarf operation.198  void addAnd(unsigned Mask);199 200  /// Emit a DW_OP_stack_value, if supported.201  ///202  /// The proper way to describe a constant value is DW_OP_constu <const>,203  /// DW_OP_stack_value.  Unfortunately, DW_OP_stack_value was not available204  /// until DWARF 4, so we will continue to generate DW_OP_constu <const> for205  /// DWARF 2 and DWARF 3. Technically, this is incorrect since DW_OP_const206  /// <const> actually describes a value at a constant address, not a constant207  /// value.  However, in the past there was no better way to describe a208  /// constant value, so the producers and consumers started to rely on209  /// heuristics to disambiguate the value vs. location status of the210  /// expression.  See PR21176 for more details.211  void addStackValue();212 213  /// Finalize an entry value by emitting its size operand, and committing the214  /// DWARF block which has been emitted to the temporary buffer.215  void finalizeEntryValue();216 217  /// Cancel the emission of an entry value.218  void cancelEntryValue();219 220  ~DwarfExpression() = default;221 222public:223  DwarfExpression(unsigned DwarfVersion, DwarfCompileUnit &CU)224      : CU(CU), SubRegisterSizeInBits(0), SubRegisterOffsetInBits(0),225        LocationKind(Unknown), SavedLocationKind(Unknown),226        LocationFlags(Unknown), DwarfVersion(DwarfVersion) {}227 228  /// This needs to be called last to commit any pending changes.229  void finalize();230 231  /// Emit a boolean constant.232  void addBooleanConstant(int64_t Value);233 234  /// Emit a signed constant.235  void addSignedConstant(int64_t Value);236 237  /// Emit an unsigned constant.238  void addUnsignedConstant(uint64_t Value);239 240  /// Emit an unsigned constant.241  void addUnsignedConstant(const APInt &Value);242 243  /// Emit an floating point constant.244  void addConstantFP(const APFloat &Value, const AsmPrinter &AP);245 246  /// Lock this down to become a memory location description.247  void setMemoryLocationKind() {248    assert(isUnknownLocation());249    LocationKind = Memory;250  }251 252  /// Lock this down to become an entry value location.253  void setEntryValueFlags(const MachineLocation &Loc);254 255  /// Lock this down to become a call site parameter location.256  void setCallSiteParamValueFlag() { LocationFlags |= CallSiteParamValue; }257 258  /// Emit a machine register location. As an optimization this may also consume259  /// the prefix of a DwarfExpression if a more efficient representation for260  /// combining the register location and the first operation exists.261  ///262  /// \param FragmentOffsetInBits     If this is one fragment out of a263  /// fragmented264  ///                                 location, this is the offset of the265  ///                                 fragment inside the entire variable.266  /// \return                         false if no DWARF register exists267  ///                                 for MachineReg.268  bool addMachineRegExpression(const TargetRegisterInfo &TRI,269                               DIExpressionCursor &Expr,270                               llvm::Register MachineReg,271                               unsigned FragmentOffsetInBits = 0);272 273  /// Begin emission of an entry value dwarf operation. The entry value's274  /// first operand is the size of the DWARF block (its second operand),275  /// which needs to be calculated at time of emission, so we don't emit276  /// any operands here.277  void beginEntryValueExpression(DIExpressionCursor &ExprCursor);278 279  /// Return the index of a base type with the given properties and280  /// create one if necessary.281  unsigned getOrCreateBaseType(unsigned BitSize, dwarf::TypeKind Encoding);282 283  /// Emit all remaining operations in the DIExpressionCursor. The284  /// cursor must not contain any DW_OP_LLVM_arg operations.285  void addExpression(DIExpressionCursor &&Expr);286 287  /// Emit all remaining operations in the DIExpressionCursor.288  /// DW_OP_LLVM_arg operations are resolved by calling (\p InsertArg).289  //290  /// \return false if any call to (\p InsertArg) returns false.291  bool addExpression(292      DIExpressionCursor &&Expr,293      llvm::function_ref<bool(unsigned, DIExpressionCursor &)> InsertArg);294 295  /// If applicable, emit an empty DW_OP_piece / DW_OP_bit_piece to advance to296  /// the fragment described by \c Expr.297  void addFragmentOffset(const DIExpression *Expr);298 299  void emitLegacySExt(unsigned FromBits);300  void emitLegacyZExt(unsigned FromBits);301 302  /// Emit location information expressed via WebAssembly location + offset303  /// The Index is an identifier for locals, globals or operand stack.304  void addWasmLocation(unsigned Index, uint64_t Offset);305};306 307/// DwarfExpression implementation for .debug_loc entries.308class DebugLocDwarfExpression final : public DwarfExpression {309 310  struct TempBuffer {311    SmallString<32> Bytes;312    std::vector<std::string> Comments;313    BufferByteStreamer BS;314 315    TempBuffer(bool GenerateComments) : BS(Bytes, Comments, GenerateComments) {}316  };317 318  std::unique_ptr<TempBuffer> TmpBuf;319  BufferByteStreamer &OutBS;320  bool IsBuffering = false;321 322  /// Return the byte streamer that currently is being emitted to.323  ByteStreamer &getActiveStreamer() { return IsBuffering ? TmpBuf->BS : OutBS; }324 325  void emitOp(uint8_t Op, const char *Comment = nullptr) override;326  void emitSigned(int64_t Value) override;327  void emitUnsigned(uint64_t Value) override;328  void emitData1(uint8_t Value) override;329  void emitBaseTypeRef(uint64_t Idx) override;330 331  void enableTemporaryBuffer() override;332  void disableTemporaryBuffer() override;333  unsigned getTemporaryBufferSize() override;334  void commitTemporaryBuffer() override;335 336  bool isFrameRegister(const TargetRegisterInfo &TRI,337                       llvm::Register MachineReg) override;338 339public:340  DebugLocDwarfExpression(unsigned DwarfVersion, BufferByteStreamer &BS,341                          DwarfCompileUnit &CU)342      : DwarfExpression(DwarfVersion, CU), OutBS(BS) {}343};344 345/// DwarfExpression implementation for singular DW_AT_location.346class DIEDwarfExpression final : public DwarfExpression {347  const AsmPrinter &AP;348  DIELoc &OutDIE;349  DIELoc TmpDIE;350  bool IsBuffering = false;351 352  /// Return the DIE that currently is being emitted to.353  DIELoc &getActiveDIE() { return IsBuffering ? TmpDIE : OutDIE; }354 355  void emitOp(uint8_t Op, const char *Comment = nullptr) override;356  void emitSigned(int64_t Value) override;357  void emitUnsigned(uint64_t Value) override;358  void emitData1(uint8_t Value) override;359  void emitBaseTypeRef(uint64_t Idx) override;360 361  void enableTemporaryBuffer() override;362  void disableTemporaryBuffer() override;363  unsigned getTemporaryBufferSize() override;364  void commitTemporaryBuffer() override;365 366  bool isFrameRegister(const TargetRegisterInfo &TRI,367                       llvm::Register MachineReg) override;368 369public:370  DIEDwarfExpression(const AsmPrinter &AP, DwarfCompileUnit &CU, DIELoc &DIE);371 372  DIELoc *finalize() {373    DwarfExpression::finalize();374    return &OutDIE;375  }376};377 378} // end namespace llvm379 380#endif // LLVM_LIB_CODEGEN_ASMPRINTER_DWARFEXPRESSION_H381