1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 03:02:36 +01:00
llvm-mirror/include/llvm/MC/MCFragment.h
Hongtao Yu 85e4f6f241 [CSSPGO] Pseudo probe encoding and emission.
This change implements pseudo probe encoding and emission for CSSPGO. Please see RFC here for more context: https://groups.google.com/g/llvm-dev/c/1p1rdYbL93s

Pseudo probes are in the form of intrinsic calls on IR/MIR but they do not turn into any machine instructions. Instead they are emitted into the binary as a piece of data in standalone sections.  The probe-specific sections are not needed to be loaded into memory at execution time, thus they do not incur a runtime overhead. 

**ELF object emission**

The binary data to emit are organized as two ELF sections, i.e, the `.pseudo_probe_desc` section and the `.pseudo_probe` section. The `.pseudo_probe_desc` section stores a function descriptor for each function and the `.pseudo_probe` section stores the actual probes, each fo which corresponds to an IR basic block or an IR function callsite. A function descriptor is stored as a module-level metadata during the compilation and is serialized into the object file during object emission.

Both the probe descriptors and pseudo probes can be emitted into a separate ELF section per function to leverage the linker for deduplication.  A `.pseudo_probe` section shares the same COMDAT group with the function code so that when the function is dead, the probes are dead and disposed too. On the contrary, a `.pseudo_probe_desc` section has its own COMDAT group. This is because even if a function is dead, its probes may be inlined into other functions and its descriptor is still needed by the profile generation tool.

The format of `.pseudo_probe_desc` section looks like:

```
.section   .pseudo_probe_desc,"",@progbits
.quad   6309742469962978389  // Func GUID
.quad   4294967295           // Func Hash
.byte   9                    // Length of func name
.ascii  "_Z5funcAi"          // Func name
.quad   7102633082150537521
.quad   138828622701
.byte   12
.ascii  "_Z8funcLeafi"
.quad   446061515086924981
.quad   4294967295
.byte   9
.ascii  "_Z5funcBi"
.quad   -2016976694713209516
.quad   72617220756
.byte   7
.ascii  "_Z3fibi"
```

For each `.pseudoprobe` section, the encoded binary data consists of a single function record corresponding to an outlined function (i.e, a function with a code entry in the `.text` section). A function record has the following format :

```
FUNCTION BODY (one for each outlined function present in the text section)
    GUID (uint64)
        GUID of the function
    NPROBES (ULEB128)
        Number of probes originating from this function.
    NUM_INLINED_FUNCTIONS (ULEB128)
        Number of callees inlined into this function, aka number of
        first-level inlinees
    PROBE RECORDS
        A list of NPROBES entries. Each entry contains:
          INDEX (ULEB128)
          TYPE (uint4)
            0 - block probe, 1 - indirect call, 2 - direct call
          ATTRIBUTE (uint3)
            reserved
          ADDRESS_TYPE (uint1)
            0 - code address, 1 - address delta
          CODE_ADDRESS (uint64 or ULEB128)
            code address or address delta, depending on ADDRESS_TYPE
    INLINED FUNCTION RECORDS
        A list of NUM_INLINED_FUNCTIONS entries describing each of the inlined
        callees.  Each record contains:
          INLINE SITE
            GUID of the inlinee (uint64)
            ID of the callsite probe (ULEB128)
          FUNCTION BODY
            A FUNCTION BODY entry describing the inlined function.
```

To support building a context-sensitive profile, probes from inlinees are grouped by their inline contexts. An inline context is logically a call path through which a callee function lands in a caller function. The probe emitter builds an inline tree based on the debug metadata for each outlined function in the form of a trie tree. A tree root is the outlined function. Each tree edge stands for a callsite where inlining happens. Pseudo probes originating from an inlinee function are stored in a tree node and the tree path starting from the root all the way down to the tree node is the inline context of the probes. The emission happens on the whole tree top-down recursively. Probes of a tree node will be emitted altogether with their direct parent edge. Since a pseudo probe corresponds to a real code address, for size savings, the address is encoded as a delta from the previous probe except for the first probe. Variant-sized integer encoding, aka LEB128, is used for address delta and probe index.

**Assembling**

Pseudo probes can be printed as assembly directives alternatively. This allows for good assembly code readability and also provides a view of how optimizations and pseudo probes affect each other, especially helpful for diff time assembly analysis.

A pseudo probe directive has the following operands in order: function GUID, probe index, probe type, probe attributes and inline context. The directive is generated by the compiler and can be parsed by the assembler to form an encoded `.pseudoprobe` section in the object file.

A example assembly looks like:

```
foo2: # @foo2
# %bb.0: # %bb0
pushq %rax
testl %edi, %edi
.pseudoprobe 837061429793323041 1 0 0
je .LBB1_1
# %bb.2: # %bb2
.pseudoprobe 837061429793323041 6 2 0
callq foo
.pseudoprobe 837061429793323041 3 0 0
.pseudoprobe 837061429793323041 4 0 0
popq %rax
retq
.LBB1_1: # %bb1
.pseudoprobe 837061429793323041 5 1 0
callq *%rsi
.pseudoprobe 837061429793323041 2 0 0
.pseudoprobe 837061429793323041 4 0 0
popq %rax
retq
# -- End function
.section .pseudo_probe_desc,"",@progbits
.quad 6699318081062747564
.quad 72617220756
.byte 3
.ascii "foo"
.quad 837061429793323041
.quad 281547593931412
.byte 4
.ascii "foo2"
```

With inlining turned on, the assembly may look different around %bb2 with an inlined probe:

```
# %bb.2:                                # %bb2
.pseudoprobe    837061429793323041 3 0
.pseudoprobe    6699318081062747564 1 0 @ 837061429793323041:6
.pseudoprobe    837061429793323041 4 0
popq    %rax
retq
```

**Disassembling**

We have a disassembling tool (llvm-profgen) that can display disassembly alongside with pseudo probes. So far it only supports ELF executable file.

An example disassembly looks like:

```
00000000002011a0 <foo2>:
  2011a0: 50                    push   rax
  2011a1: 85 ff                 test   edi,edi
  [Probe]:  FUNC: foo2  Index: 1  Type: Block
  2011a3: 74 02                 je     2011a7 <foo2+0x7>
  [Probe]:  FUNC: foo2  Index: 3  Type: Block
  [Probe]:  FUNC: foo2  Index: 4  Type: Block
  [Probe]:  FUNC: foo   Index: 1  Type: Block  Inlined: @ foo2:6
  2011a5: 58                    pop    rax
  2011a6: c3                    ret
  [Probe]:  FUNC: foo2  Index: 2  Type: Block
  2011a7: bf 01 00 00 00        mov    edi,0x1
  [Probe]:  FUNC: foo2  Index: 5  Type: IndirectCall
  2011ac: ff d6                 call   rsi
  [Probe]:  FUNC: foo2  Index: 4  Type: Block
  2011ae: 58                    pop    rax
  2011af: c3                    ret
```

Reviewed By: wmi

Differential Revision: https://reviews.llvm.org/D91878
2020-12-10 17:29:28 -08:00

616 lines
19 KiB
C++

//===- MCFragment.h - Fragment type hierarchy -------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_MC_MCFRAGMENT_H
#define LLVM_MC_MCFRAGMENT_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/ilist_node.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCInst.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/SMLoc.h"
#include <cstdint>
#include <utility>
namespace llvm {
class MCSection;
class MCSubtargetInfo;
class MCSymbol;
class MCFragment : public ilist_node_with_parent<MCFragment, MCSection> {
friend class MCAsmLayout;
public:
enum FragmentType : uint8_t {
FT_Align,
FT_Data,
FT_CompactEncodedInst,
FT_Fill,
FT_Nops,
FT_Relaxable,
FT_Org,
FT_Dwarf,
FT_DwarfFrame,
FT_LEB,
FT_BoundaryAlign,
FT_SymbolId,
FT_CVInlineLines,
FT_CVDefRange,
FT_PseudoProbe,
FT_Dummy
};
private:
/// The data for the section this fragment is in.
MCSection *Parent;
/// The atom this fragment is in, as represented by its defining symbol.
const MCSymbol *Atom;
/// The offset of this fragment in its section. This is ~0 until
/// initialized.
uint64_t Offset;
/// The layout order of this fragment.
unsigned LayoutOrder;
/// The subsection this fragment belongs to. This is 0 if the fragment is not
// in any subsection.
unsigned SubsectionNumber = 0;
FragmentType Kind;
/// Whether fragment is being laid out.
bool IsBeingLaidOut;
protected:
bool HasInstructions;
MCFragment(FragmentType Kind, bool HasInstructions,
MCSection *Parent = nullptr);
public:
MCFragment() = delete;
MCFragment(const MCFragment &) = delete;
MCFragment &operator=(const MCFragment &) = delete;
/// Destroys the current fragment.
///
/// This must be used instead of delete as MCFragment is non-virtual.
/// This method will dispatch to the appropriate subclass.
void destroy();
FragmentType getKind() const { return Kind; }
MCSection *getParent() const { return Parent; }
void setParent(MCSection *Value) { Parent = Value; }
const MCSymbol *getAtom() const { return Atom; }
void setAtom(const MCSymbol *Value) { Atom = Value; }
unsigned getLayoutOrder() const { return LayoutOrder; }
void setLayoutOrder(unsigned Value) { LayoutOrder = Value; }
/// Does this fragment have instructions emitted into it? By default
/// this is false, but specific fragment types may set it to true.
bool hasInstructions() const { return HasInstructions; }
void dump() const;
void setSubsectionNumber(unsigned Value) { SubsectionNumber = Value; }
unsigned getSubsectionNumber() const { return SubsectionNumber; }
};
class MCDummyFragment : public MCFragment {
public:
explicit MCDummyFragment(MCSection *Sec) : MCFragment(FT_Dummy, false, Sec) {}
static bool classof(const MCFragment *F) { return F->getKind() == FT_Dummy; }
};
/// Interface implemented by fragments that contain encoded instructions and/or
/// data.
///
class MCEncodedFragment : public MCFragment {
/// Should this fragment be aligned to the end of a bundle?
bool AlignToBundleEnd = false;
uint8_t BundlePadding = 0;
protected:
MCEncodedFragment(MCFragment::FragmentType FType, bool HasInstructions,
MCSection *Sec)
: MCFragment(FType, HasInstructions, Sec) {}
/// The MCSubtargetInfo in effect when the instruction was encoded.
/// It must be non-null for instructions.
const MCSubtargetInfo *STI = nullptr;
public:
static bool classof(const MCFragment *F) {
MCFragment::FragmentType Kind = F->getKind();
switch (Kind) {
default:
return false;
case MCFragment::FT_Relaxable:
case MCFragment::FT_CompactEncodedInst:
case MCFragment::FT_Data:
case MCFragment::FT_Dwarf:
case MCFragment::FT_DwarfFrame:
case MCFragment::FT_PseudoProbe:
return true;
}
}
/// Should this fragment be placed at the end of an aligned bundle?
bool alignToBundleEnd() const { return AlignToBundleEnd; }
void setAlignToBundleEnd(bool V) { AlignToBundleEnd = V; }
/// Get the padding size that must be inserted before this fragment.
/// Used for bundling. By default, no padding is inserted.
/// Note that padding size is restricted to 8 bits. This is an optimization
/// to reduce the amount of space used for each fragment. In practice, larger
/// padding should never be required.
uint8_t getBundlePadding() const { return BundlePadding; }
/// Set the padding size for this fragment. By default it's a no-op,
/// and only some fragments have a meaningful implementation.
void setBundlePadding(uint8_t N) { BundlePadding = N; }
/// Retrieve the MCSubTargetInfo in effect when the instruction was encoded.
/// Guaranteed to be non-null if hasInstructions() == true
const MCSubtargetInfo *getSubtargetInfo() const { return STI; }
/// Record that the fragment contains instructions with the MCSubtargetInfo in
/// effect when the instruction was encoded.
void setHasInstructions(const MCSubtargetInfo &STI) {
HasInstructions = true;
this->STI = &STI;
}
};
/// Interface implemented by fragments that contain encoded instructions and/or
/// data.
///
template<unsigned ContentsSize>
class MCEncodedFragmentWithContents : public MCEncodedFragment {
SmallVector<char, ContentsSize> Contents;
protected:
MCEncodedFragmentWithContents(MCFragment::FragmentType FType,
bool HasInstructions,
MCSection *Sec)
: MCEncodedFragment(FType, HasInstructions, Sec) {}
public:
SmallVectorImpl<char> &getContents() { return Contents; }
const SmallVectorImpl<char> &getContents() const { return Contents; }
};
/// Interface implemented by fragments that contain encoded instructions and/or
/// data and also have fixups registered.
///
template<unsigned ContentsSize, unsigned FixupsSize>
class MCEncodedFragmentWithFixups :
public MCEncodedFragmentWithContents<ContentsSize> {
/// The list of fixups in this fragment.
SmallVector<MCFixup, FixupsSize> Fixups;
protected:
MCEncodedFragmentWithFixups(MCFragment::FragmentType FType,
bool HasInstructions,
MCSection *Sec)
: MCEncodedFragmentWithContents<ContentsSize>(FType, HasInstructions,
Sec) {}
public:
using const_fixup_iterator = SmallVectorImpl<MCFixup>::const_iterator;
using fixup_iterator = SmallVectorImpl<MCFixup>::iterator;
SmallVectorImpl<MCFixup> &getFixups() { return Fixups; }
const SmallVectorImpl<MCFixup> &getFixups() const { return Fixups; }
fixup_iterator fixup_begin() { return Fixups.begin(); }
const_fixup_iterator fixup_begin() const { return Fixups.begin(); }
fixup_iterator fixup_end() { return Fixups.end(); }
const_fixup_iterator fixup_end() const { return Fixups.end(); }
static bool classof(const MCFragment *F) {
MCFragment::FragmentType Kind = F->getKind();
return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data ||
Kind == MCFragment::FT_CVDefRange || Kind == MCFragment::FT_Dwarf ||
Kind == MCFragment::FT_DwarfFrame;
}
};
/// Fragment for data and encoded instructions.
///
class MCDataFragment : public MCEncodedFragmentWithFixups<32, 4> {
public:
MCDataFragment(MCSection *Sec = nullptr)
: MCEncodedFragmentWithFixups<32, 4>(FT_Data, false, Sec) {}
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_Data;
}
};
/// This is a compact (memory-size-wise) fragment for holding an encoded
/// instruction (non-relaxable) that has no fixups registered. When applicable,
/// it can be used instead of MCDataFragment and lead to lower memory
/// consumption.
///
class MCCompactEncodedInstFragment : public MCEncodedFragmentWithContents<4> {
public:
MCCompactEncodedInstFragment(MCSection *Sec = nullptr)
: MCEncodedFragmentWithContents(FT_CompactEncodedInst, true, Sec) {
}
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_CompactEncodedInst;
}
};
/// A relaxable fragment holds on to its MCInst, since it may need to be
/// relaxed during the assembler layout and relaxation stage.
///
class MCRelaxableFragment : public MCEncodedFragmentWithFixups<8, 1> {
/// The instruction this is a fragment for.
MCInst Inst;
/// Can we auto pad the instruction?
bool AllowAutoPadding = false;
public:
MCRelaxableFragment(const MCInst &Inst, const MCSubtargetInfo &STI,
MCSection *Sec = nullptr)
: MCEncodedFragmentWithFixups(FT_Relaxable, true, Sec),
Inst(Inst) { this->STI = &STI; }
const MCInst &getInst() const { return Inst; }
void setInst(const MCInst &Value) { Inst = Value; }
bool getAllowAutoPadding() const { return AllowAutoPadding; }
void setAllowAutoPadding(bool V) { AllowAutoPadding = V; }
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_Relaxable;
}
};
class MCAlignFragment : public MCFragment {
/// The alignment to ensure, in bytes.
unsigned Alignment;
/// Flag to indicate that (optimal) NOPs should be emitted instead
/// of using the provided value. The exact interpretation of this flag is
/// target dependent.
bool EmitNops : 1;
/// Value to use for filling padding bytes.
int64_t Value;
/// The size of the integer (in bytes) of \p Value.
unsigned ValueSize;
/// The maximum number of bytes to emit; if the alignment
/// cannot be satisfied in this width then this fragment is ignored.
unsigned MaxBytesToEmit;
public:
MCAlignFragment(unsigned Alignment, int64_t Value, unsigned ValueSize,
unsigned MaxBytesToEmit, MCSection *Sec = nullptr)
: MCFragment(FT_Align, false, Sec), Alignment(Alignment), EmitNops(false),
Value(Value), ValueSize(ValueSize), MaxBytesToEmit(MaxBytesToEmit) {}
unsigned getAlignment() const { return Alignment; }
int64_t getValue() const { return Value; }
unsigned getValueSize() const { return ValueSize; }
unsigned getMaxBytesToEmit() const { return MaxBytesToEmit; }
bool hasEmitNops() const { return EmitNops; }
void setEmitNops(bool Value) { EmitNops = Value; }
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_Align;
}
};
class MCFillFragment : public MCFragment {
uint8_t ValueSize;
/// Value to use for filling bytes.
uint64_t Value;
/// The number of bytes to insert.
const MCExpr &NumValues;
/// Source location of the directive that this fragment was created for.
SMLoc Loc;
public:
MCFillFragment(uint64_t Value, uint8_t VSize, const MCExpr &NumValues,
SMLoc Loc, MCSection *Sec = nullptr)
: MCFragment(FT_Fill, false, Sec), ValueSize(VSize), Value(Value),
NumValues(NumValues), Loc(Loc) {}
uint64_t getValue() const { return Value; }
uint8_t getValueSize() const { return ValueSize; }
const MCExpr &getNumValues() const { return NumValues; }
SMLoc getLoc() const { return Loc; }
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_Fill;
}
};
class MCNopsFragment : public MCFragment {
/// The number of bytes to insert.
int64_t Size;
/// Maximum number of bytes allowed in each NOP instruction.
int64_t ControlledNopLength;
/// Source location of the directive that this fragment was created for.
SMLoc Loc;
public:
MCNopsFragment(int64_t NumBytes, int64_t ControlledNopLength, SMLoc L,
MCSection *Sec = nullptr)
: MCFragment(FT_Nops, false, Sec), Size(NumBytes),
ControlledNopLength(ControlledNopLength), Loc(L) {}
int64_t getNumBytes() const { return Size; }
int64_t getControlledNopLength() const { return ControlledNopLength; }
SMLoc getLoc() const { return Loc; }
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_Nops;
}
};
class MCOrgFragment : public MCFragment {
/// Value to use for filling bytes.
int8_t Value;
/// The offset this fragment should start at.
const MCExpr *Offset;
/// Source location of the directive that this fragment was created for.
SMLoc Loc;
public:
MCOrgFragment(const MCExpr &Offset, int8_t Value, SMLoc Loc,
MCSection *Sec = nullptr)
: MCFragment(FT_Org, false, Sec), Value(Value), Offset(&Offset),
Loc(Loc) {}
const MCExpr &getOffset() const { return *Offset; }
uint8_t getValue() const { return Value; }
SMLoc getLoc() const { return Loc; }
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_Org;
}
};
class MCLEBFragment : public MCFragment {
/// True if this is a sleb128, false if uleb128.
bool IsSigned;
/// The value this fragment should contain.
const MCExpr *Value;
SmallString<8> Contents;
public:
MCLEBFragment(const MCExpr &Value_, bool IsSigned_, MCSection *Sec = nullptr)
: MCFragment(FT_LEB, false, Sec), IsSigned(IsSigned_), Value(&Value_) {
Contents.push_back(0);
}
const MCExpr &getValue() const { return *Value; }
bool isSigned() const { return IsSigned; }
SmallString<8> &getContents() { return Contents; }
const SmallString<8> &getContents() const { return Contents; }
/// @}
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_LEB;
}
};
class MCDwarfLineAddrFragment : public MCEncodedFragmentWithFixups<8, 1> {
/// The value of the difference between the two line numbers
/// between two .loc dwarf directives.
int64_t LineDelta;
/// The expression for the difference of the two symbols that
/// make up the address delta between two .loc dwarf directives.
const MCExpr *AddrDelta;
public:
MCDwarfLineAddrFragment(int64_t LineDelta, const MCExpr &AddrDelta,
MCSection *Sec = nullptr)
: MCEncodedFragmentWithFixups<8, 1>(FT_Dwarf, false, Sec),
LineDelta(LineDelta), AddrDelta(&AddrDelta) {}
int64_t getLineDelta() const { return LineDelta; }
const MCExpr &getAddrDelta() const { return *AddrDelta; }
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_Dwarf;
}
};
class MCDwarfCallFrameFragment : public MCEncodedFragmentWithFixups<8, 1> {
/// The expression for the difference of the two symbols that
/// make up the address delta between two .cfi_* dwarf directives.
const MCExpr *AddrDelta;
public:
MCDwarfCallFrameFragment(const MCExpr &AddrDelta, MCSection *Sec = nullptr)
: MCEncodedFragmentWithFixups<8, 1>(FT_DwarfFrame, false, Sec),
AddrDelta(&AddrDelta) {}
const MCExpr &getAddrDelta() const { return *AddrDelta; }
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_DwarfFrame;
}
};
/// Represents a symbol table index fragment.
class MCSymbolIdFragment : public MCFragment {
const MCSymbol *Sym;
public:
MCSymbolIdFragment(const MCSymbol *Sym, MCSection *Sec = nullptr)
: MCFragment(FT_SymbolId, false, Sec), Sym(Sym) {}
const MCSymbol *getSymbol() { return Sym; }
const MCSymbol *getSymbol() const { return Sym; }
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_SymbolId;
}
};
/// Fragment representing the binary annotations produced by the
/// .cv_inline_linetable directive.
class MCCVInlineLineTableFragment : public MCFragment {
unsigned SiteFuncId;
unsigned StartFileId;
unsigned StartLineNum;
const MCSymbol *FnStartSym;
const MCSymbol *FnEndSym;
SmallString<8> Contents;
/// CodeViewContext has the real knowledge about this format, so let it access
/// our members.
friend class CodeViewContext;
public:
MCCVInlineLineTableFragment(unsigned SiteFuncId, unsigned StartFileId,
unsigned StartLineNum, const MCSymbol *FnStartSym,
const MCSymbol *FnEndSym,
MCSection *Sec = nullptr)
: MCFragment(FT_CVInlineLines, false, Sec), SiteFuncId(SiteFuncId),
StartFileId(StartFileId), StartLineNum(StartLineNum),
FnStartSym(FnStartSym), FnEndSym(FnEndSym) {}
const MCSymbol *getFnStartSym() const { return FnStartSym; }
const MCSymbol *getFnEndSym() const { return FnEndSym; }
SmallString<8> &getContents() { return Contents; }
const SmallString<8> &getContents() const { return Contents; }
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_CVInlineLines;
}
};
/// Fragment representing the .cv_def_range directive.
class MCCVDefRangeFragment : public MCEncodedFragmentWithFixups<32, 4> {
SmallVector<std::pair<const MCSymbol *, const MCSymbol *>, 2> Ranges;
SmallString<32> FixedSizePortion;
/// CodeViewContext has the real knowledge about this format, so let it access
/// our members.
friend class CodeViewContext;
public:
MCCVDefRangeFragment(
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
StringRef FixedSizePortion, MCSection *Sec = nullptr)
: MCEncodedFragmentWithFixups<32, 4>(FT_CVDefRange, false, Sec),
Ranges(Ranges.begin(), Ranges.end()),
FixedSizePortion(FixedSizePortion) {}
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> getRanges() const {
return Ranges;
}
StringRef getFixedSizePortion() const { return FixedSizePortion; }
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_CVDefRange;
}
};
/// Represents required padding such that a particular other set of fragments
/// does not cross a particular power-of-two boundary. The other fragments must
/// follow this one within the same section.
class MCBoundaryAlignFragment : public MCFragment {
/// The alignment requirement of the branch to be aligned.
Align AlignBoundary;
/// The last fragment in the set of fragments to be aligned.
const MCFragment *LastFragment = nullptr;
/// The size of the fragment. The size is lazily set during relaxation, and
/// is not meaningful before that.
uint64_t Size = 0;
public:
MCBoundaryAlignFragment(Align AlignBoundary, MCSection *Sec = nullptr)
: MCFragment(FT_BoundaryAlign, false, Sec), AlignBoundary(AlignBoundary) {
}
uint64_t getSize() const { return Size; }
void setSize(uint64_t Value) { Size = Value; }
Align getAlignment() const { return AlignBoundary; }
void setAlignment(Align Value) { AlignBoundary = Value; }
const MCFragment *getLastFragment() const { return LastFragment; }
void setLastFragment(const MCFragment *F) {
assert(!F || getParent() == F->getParent());
LastFragment = F;
}
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_BoundaryAlign;
}
};
class MCPseudoProbeAddrFragment : public MCEncodedFragmentWithFixups<8, 1> {
/// The expression for the difference of the two symbols that
/// make up the address delta between two .pseudoprobe directives.
const MCExpr *AddrDelta;
public:
MCPseudoProbeAddrFragment(const MCExpr *AddrDelta, MCSection *Sec = nullptr)
: MCEncodedFragmentWithFixups<8, 1>(FT_PseudoProbe, false, Sec),
AddrDelta(AddrDelta) {}
const MCExpr &getAddrDelta() const { return *AddrDelta; }
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_PseudoProbe;
}
};
} // end namespace llvm
#endif // LLVM_MC_MCFRAGMENT_H