39 FREInfo<endianness::native> Info;
40 bool CFARegSet =
false;
42 SFrameFRE(
const MCSymbol *Start) : Label(
Start) { Info.Info = 0; }
44 void emitOffset(MCObjectStreamer &S,
FREOffset OffsetSize,
size_t Offset) {
58 void emit(MCObjectStreamer &S,
const MCSymbol *FuncBegin,
59 MCFragment *FDEFrag) {
65 unsigned RegsTracked = 1;
70 Info.setOffsetCount(RegsTracked);
74 Info.setOffsetSize(FREOffset::B1);
76 Info.setOffsetSize(FREOffset::B2);
79 isInt<32>(RAOffset) &&
"Offset too big for sframe");
80 Info.setOffsetSize(FREOffset::B4);
84 Info.setReturnAddressSigned(
false);
90 [[maybe_unused]]
unsigned OffsetsEmitted = 1;
91 emitOffset(S, Info.getOffsetSize(), CFAOffset);
94 emitOffset(S, Info.getOffsetSize(), FPOffset);
98 emitOffset(S, Info.getOffsetSize(), RAOffset);
100 assert(OffsetsEmitted == RegsTracked &&
101 "Didn't emit the right number of offsets");
109 const MCDwarfFrameInfo &DFrame;
119 SFrameFDE(
const MCDwarfFrameInfo &
DF, MCSymbol *FRES)
120 : DFrame(
DF), FREStart(FRES), Frag(nullptr) {}
122 void emit(MCObjectStreamer &S,
const MCSymbol *FRESubSectionStart) {
126 const MCExpr *
V =
C.getAsmInfo().getExprForFDESymbol(
127 &(*DFrame.Begin),
C.getObjectFileInfo()->getFDEEncoding(), S);
171class SFrameEmitterImpl {
172 MCObjectStreamer &Streamer;
183 int8_t FixedRAOffset;
188 bool setCFARegister(SFrameFRE &FRE,
const MCCFIInstruction &
I) {
189 if (
I.getRegister() == SPReg) {
190 FRE.CFARegSet =
true;
194 if (
I.getRegister() == FPReg) {
195 FRE.CFARegSet =
true;
199 Streamer.getContext().reportWarning(
200 I.getLoc(),
"canonical Frame Address not in stack- or frame-pointer. "
201 "Omitting SFrame unwind info for this function");
205 bool setCFAOffset(SFrameFRE &FRE, SMLoc Loc,
size_t Offset) {
206 if (!FRE.CFARegSet) {
207 Streamer.getContext().reportWarning(
208 Loc,
"adjusting CFA offset without a base register. "
209 "Omitting SFrame unwind info for this function");
224 bool isCFIEscapeSafe(SFrameFDE &FDE,
const SFrameFRE &FRE,
225 const MCCFIInstruction &CFI) {
226 const MCAsmInfo &AI = Streamer.getContext().getAsmInfo();
234 dwarf::CFIProgram
P(1,
236 Streamer.getContext().getTargetTriple().getArch());
240 Streamer.getContext().reportWarning(
242 "skipping SFrame FDE; .cfi_escape with unknown effects");
248 for (
const dwarf::CFIProgram::Instruction &
I :
P) {
250 case dwarf::DW_CFA_nop:
252 case dwarf::DW_CFA_val_offset: {
256 auto Reg =
I.getOperandAsUnsigned(
P, 0);
258 assert(
Reg &&
"DW_CFA_val_offset with no register.");
261 auto Opnd =
I.getOperandAsSigned(
P, 1);
262 if (!Opnd || *Opnd != 0)
265 if (!SPOk || *
Reg == RAReg || *
Reg == FPReg) {
266 StringRef
RN = *
Reg == SPReg
268 : (*
Reg == FPReg ?
"FP reg " :
"RA reg ");
269 Streamer.getContext().reportWarning(
272 "skipping SFrame FDE; .cfi_escape DW_CFA_val_offset with ") +
277 case dwarf::DW_CFA_expression: {
280 auto Reg =
I.getOperandAsUnsigned(
P, 0);
282 Streamer.getContext().reportWarning(
284 "skipping SFrame FDE; .cfi_escape with unknown effects");
287 if (*
Reg == SPReg || *
Reg == RAReg || *
Reg == FPReg) {
288 StringRef
RN = *
Reg == SPReg
290 : (*
Reg == FPReg ?
"FP reg " :
"RA reg ");
291 Streamer.getContext().reportWarning(
294 "skipping SFrame FDE; .cfi_escape DW_CFA_expression with ") +
299 case dwarf::DW_CFA_GNU_args_size: {
300 auto Size =
I.getOperandAsSigned(
P, 0);
305 Streamer.getContext().reportWarning(
307 Twine(
"skipping SFrame FDE; .cfi_escape DW_CFA_GNU_args_size "
308 "with non frame-pointer CFA"));
316 case dwarf::DW_CFA_advance_loc:
317 case dwarf::DW_CFA_offset:
318 case dwarf::DW_CFA_restore:
319 case dwarf::DW_CFA_set_loc:
320 case dwarf::DW_CFA_advance_loc1:
321 case dwarf::DW_CFA_advance_loc2:
322 case dwarf::DW_CFA_advance_loc4:
323 case dwarf::DW_CFA_offset_extended:
324 case dwarf::DW_CFA_restore_extended:
325 case dwarf::DW_CFA_undefined:
326 case dwarf::DW_CFA_same_value:
327 case dwarf::DW_CFA_register:
328 case dwarf::DW_CFA_remember_state:
329 case dwarf::DW_CFA_restore_state:
330 case dwarf::DW_CFA_def_cfa:
331 case dwarf::DW_CFA_def_cfa_register:
332 case dwarf::DW_CFA_def_cfa_offset:
333 case dwarf::DW_CFA_def_cfa_expression:
334 case dwarf::DW_CFA_offset_extended_sf:
335 case dwarf::DW_CFA_def_cfa_sf:
336 case dwarf::DW_CFA_def_cfa_offset_sf:
337 case dwarf::DW_CFA_val_offset_sf:
338 case dwarf::DW_CFA_val_expression:
339 case dwarf::DW_CFA_MIPS_advance_loc8:
340 case dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc:
341 case dwarf::DW_CFA_AARCH64_negate_ra_state:
342 case dwarf::DW_CFA_AARCH64_set_ra_state:
343 case dwarf::DW_CFA_LLVM_def_aspace_cfa:
344 case dwarf::DW_CFA_LLVM_def_aspace_cfa_sf:
345 Streamer.getContext().reportWarning(
346 CFI.
getLoc(),
"skipping SFrame FDE; .cfi_escape "
347 "CFA expression with unknown side effects");
352 Streamer.getContext().reportWarning(
354 "skipping SFrame FDE; .cfi_escape with unknown effects");
363 bool handleCFI(SFrameFDE &FDE, SFrameFRE &FRE,
const MCCFIInstruction &CFI) {
366 return setCFARegister(FRE, CFI);
369 if (!setCFARegister(FRE, CFI))
387 return setCFAOffset(FRE, CFI.
getLoc(), FRE.CFAOffset + CFI.
getOffset());
389 if (FDE.FREs.size() == 1) {
393 Streamer.getContext().reportWarning(
394 CFI.
getLoc(),
"skipping SFrame FDE; .cfi_remember_state without "
395 "prior SFrame FRE state");
398 FDE.SaveState.push_back(FRE);
403 FRE.FPOffset = FDE.FREs.front().FPOffset;
405 FRE.RAOffset = FDE.FREs.front().RAOffset;
410 assert(!FDE.SaveState.empty() &&
411 "cfi_restore_state without cfi_save_state");
412 FRE = FDE.SaveState.pop_back_val();
417 return isCFIEscapeSafe(FDE, FRE, CFI);
426 SFrameEmitterImpl(MCObjectStreamer &Streamer)
427 : Streamer(Streamer), TotalFREs(0) {
428 assert(Streamer.getContext()
432 FDEs.reserve(Streamer.getDwarfFrameInfos().size());
433 SFrameABI = *Streamer.getContext().getObjectFileInfo()->getSFrameABIArch();
435 case ABI::AArch64EndianBig:
436 case ABI::AArch64EndianLittle:
442 case ABI::AMD64EndianLittle:
446 RAReg =
static_cast<unsigned>(INT_MAX);
452 FDESubSectionStart = Streamer.getContext().createTempSymbol();
453 FRESubSectionStart = Streamer.getContext().createTempSymbol();
454 FRESubSectionEnd = Streamer.getContext().createTempSymbol();
457 bool atSameLocation(
const MCSymbol *
Left,
const MCSymbol *
Right) {
458 return Left !=
nullptr &&
Right !=
nullptr &&
459 Left->getFragment() ==
Right->getFragment() &&
463 bool equalIgnoringLocation(
const SFrameFRE &
Left,
const SFrameFRE &
Right) {
464 return Left.CFAOffset ==
Right.CFAOffset &&
466 Left.Info.getFREInfo() ==
Right.Info.getFREInfo() &&
470 void buildSFDE(
const MCDwarfFrameInfo &
DF) {
474 if (atSameLocation(
DF.Begin,
DF.End))
477 SFrameFDE FDE(
DF, Streamer.getContext().createTempSymbol());
484 if (
DF.RAReg != RAReg) {
485 Streamer.getContext().reportWarning(
486 SMLoc(),
"non-default RA register in .cfi_return_column " +
488 ". Omitting SFrame unwind info for this function");
492 SFrameFRE BaseFRE(LastLabel);
494 for (
const auto &CFI :
495 Streamer.getContext().getAsmInfo().getInitialFrameState())
496 if (!handleCFI(FDE, BaseFRE, CFI))
499 FDE.FREs.push_back(BaseFRE);
501 for (
const auto &CFI :
DF.Instructions) {
509 if (L && !
L->isDefined())
512 SFrameFRE FRE = FDE.FREs.back();
513 if (!handleCFI(FDE, FRE, CFI))
517 if (equalIgnoringLocation(FRE, FDE.FREs.back()))
522 if (atSameLocation(LastLabel, L))
523 FDE.FREs.back() = FRE;
525 FDE.FREs.push_back(FRE);
526 FDE.FREs.back().Label =
L;
533 TotalFREs += FDE.FREs.size();
537 void emitPreamble() {
538 Streamer.emitInt16(
Magic);
539 Streamer.emitInt8(
static_cast<uint8_t
>(Version::V2));
540 Streamer.emitInt8(
static_cast<uint8_t
>(Flags::FDEFuncStartPCRel));
546 Streamer.emitInt8(
static_cast<uint8_t
>(SFrameABI));
548 Streamer.emitInt8(0);
550 Streamer.emitInt8(FixedRAOffset);
552 Streamer.emitInt8(0);
554 Streamer.emitInt32(FDEs.size());
556 Streamer.emitInt32(TotalFREs);
559 Streamer.emitAbsoluteSymbolDiff(FRESubSectionEnd, FRESubSectionStart,
562 Streamer.emitInt32(0);
564 Streamer.emitInt32(FDEs.size() *
565 sizeof(sframe::FuncDescEntry<endianness::native>));
569 Streamer.emitLabel(FDESubSectionStart);
570 for (
auto &FDE : FDEs) {
571 FDE.emit(Streamer, FRESubSectionStart);
576 Streamer.emitLabel(FRESubSectionStart);
577 for (
auto &FDE : FDEs) {
578 Streamer.emitLabel(FDE.FREStart);
579 for (
auto &FRE : FDE.FREs)
580 FRE.emit(Streamer, FDE.DFrame.
Begin, FDE.Frag);
582 Streamer.emitLabel(FRESubSectionEnd);
599 SFrameEmitterImpl
Emitter(Streamer);
604 for (
const auto &DFrame : FrameArray)
607 MCSection *Section = Context.getObjectFileInfo()->getSFrameSection();
609 Section->ensureMinAlignment(
Align(8));
611 MCSymbol *SectionStart = Context.createTempSymbol();
622 if (FDEFrag ==
nullptr) {
630 I.setFREType(FREType::Addr1);
632 I.setFREType(FREType::Addr2);
635 I.setFREType(FREType::Addr4);
637 I.setFDEType(FDEType::PCInc);
648 I.Info = FDEData.back();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
dxil DXContainer Global Emitter
static RegisterPass< DebugifyFunctionPass > DF("debugify-function", "Attach debug info to a function")
This file contains data-structure definitions and constants to support unwinding based on ....
Represent a constant reference to an array (0 or more elements consecutively in memory),...
bool isLittleEndian() const
True if the target is little endian.
unsigned getCodePointerSize() const
Get the code pointer size in bytes.
static const MCBinaryExpr * createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
MCSymbol * getLabel() const
unsigned getRegister() const
OpType getOperation() const
StringRef getValues() const
int64_t getOffset() const
Context object for machine code objects.
const MCObjectFileInfo * getObjectFileInfo() const
static MCFixupKind getDataKindForSize(unsigned Size)
Return the generic fixup kind for a value with the given size.
static MCFixup create(uint32_t Offset, const MCExpr *Value, MCFixupKind Kind, bool PCRel=false)
Consider bit fields if we need more flags.
MutableArrayRef< char > getVarContents()
std::optional< sframe::ABI > getSFrameABIArch() const
Streaming object file generation interface.
void emitSFrameCalculateFuncOffset(const MCSymbol *FunCabsel, const MCSymbol *FREBegin, MCFragment *FDEFrag, SMLoc Loc)
void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc()) override
Emit a label for Symbol into the current section.
void emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) override
Emit the absolute difference between two symbols if possible.
static LLVM_ABI void emit(MCObjectStreamer &Streamer)
static LLVM_ABI void encodeFuncOffset(MCContext &C, uint64_t Offset, SmallVectorImpl< char > &Out, MCFragment *FDEFrag)
Instances of this class represent a uniqued identifier for a section in the current translation unit.
MCFragment * getCurrentFragment() const
MCContext & getContext() const
void emitValue(const MCExpr *Value, unsigned Size, SMLoc Loc=SMLoc())
void emitInt16(uint64_t Value)
ArrayRef< MCDwarfFrameInfo > getDwarfFrameInfos() const
virtual void switchSection(MCSection *Section, uint32_t Subsec=0)
Set the current section where code is being emitted to Section.
void emitInt32(uint64_t Value)
void emitInt8(uint64_t Value)
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
constexpr size_t size() const
Get the string size.
@ C
The default llvm calling convention, compatible with C.
@ Valid
The data is already valid.
FREOffset
Size of stack offsets. Bits 6-7 of FREInfo.Info.
FREType
SFrame FRE Types. Bits 0-3 of FuncDescEntry.Info.
void write(void *memory, value_type value, endianness endian)
Write a value to memory with a particular endianness.
This is an optimization pass for GlobalISel generic memory operations.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
This struct is a compact representation of a valid (non-zero power of two) alignment.
BaseReg getBaseRegister() const
void setBaseRegister(BaseReg Reg)