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;
191 FRE.Info.setBaseRegister(BaseReg::SP);
194 if (
I.getRegister() == FPReg) {
195 FRE.CFARegSet =
true;
196 FRE.Info.setBaseRegister(BaseReg::FP);
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);
304 if (
FRE.Info.getBaseRegister() != BaseReg::FP) {
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_LLVM_def_aspace_cfa:
343 case dwarf::DW_CFA_LLVM_def_aspace_cfa_sf:
344 Streamer.getContext().reportWarning(
345 CFI.
getLoc(),
"skipping SFrame FDE; .cfi_escape "
346 "CFA expression with unknown side effects");
351 Streamer.getContext().reportWarning(
353 "skipping SFrame FDE; .cfi_escape with unknown effects");
362 bool handleCFI(SFrameFDE &FDE, SFrameFRE &FRE,
const MCCFIInstruction &CFI) {
365 return setCFARegister(FRE, CFI);
368 if (!setCFARegister(FRE, CFI))
388 if (FDE.FREs.size() == 1) {
392 Streamer.getContext().reportWarning(
393 CFI.
getLoc(),
"skipping SFrame FDE; .cfi_remember_state without "
394 "prior SFrame FRE state");
397 FDE.SaveState.push_back(FRE);
402 FRE.FPOffset = FDE.FREs.front().FPOffset;
404 FRE.RAOffset = FDE.FREs.front().RAOffset;
409 assert(!FDE.SaveState.empty() &&
410 "cfi_restore_state without cfi_save_state");
411 FRE = FDE.SaveState.pop_back_val();
416 return isCFIEscapeSafe(FDE, FRE, CFI);
425 SFrameEmitterImpl(MCObjectStreamer &Streamer)
426 : Streamer(Streamer), TotalFREs(0) {
427 assert(Streamer.getContext()
431 FDEs.reserve(Streamer.getDwarfFrameInfos().size());
432 SFrameABI = *Streamer.getContext().getObjectFileInfo()->getSFrameABIArch();
434 case ABI::AArch64EndianBig:
435 case ABI::AArch64EndianLittle:
441 case ABI::AMD64EndianLittle:
445 RAReg =
static_cast<unsigned>(INT_MAX);
451 FDESubSectionStart = Streamer.getContext().createTempSymbol();
452 FRESubSectionStart = Streamer.getContext().createTempSymbol();
453 FRESubSectionEnd = Streamer.getContext().createTempSymbol();
456 bool atSameLocation(
const MCSymbol *
Left,
const MCSymbol *
Right) {
457 return Left !=
nullptr &&
Right !=
nullptr &&
458 Left->getFragment() ==
Right->getFragment() &&
462 bool equalIgnoringLocation(
const SFrameFRE &
Left,
const SFrameFRE &
Right) {
463 return Left.CFAOffset ==
Right.CFAOffset &&
465 Left.Info.getFREInfo() ==
Right.Info.getFREInfo() &&
469 void buildSFDE(
const MCDwarfFrameInfo &
DF) {
473 if (atSameLocation(
DF.Begin,
DF.End))
476 SFrameFDE FDE(
DF, Streamer.getContext().createTempSymbol());
483 if (
DF.RAReg != RAReg) {
484 Streamer.getContext().reportWarning(
485 SMLoc(),
"non-default RA register in .cfi_return_column " +
487 ". Omitting SFrame unwind info for this function");
491 SFrameFRE BaseFRE(LastLabel);
493 for (
const auto &CFI :
494 Streamer.getContext().getAsmInfo()->getInitialFrameState())
495 if (!handleCFI(FDE, BaseFRE, CFI))
498 FDE.FREs.push_back(BaseFRE);
500 for (
const auto &CFI :
DF.Instructions) {
508 if (L && !
L->isDefined())
511 SFrameFRE
FRE = FDE.FREs.back();
512 if (!handleCFI(FDE, FRE, CFI))
516 if (equalIgnoringLocation(FRE, FDE.FREs.back()))
521 if (atSameLocation(LastLabel, L))
522 FDE.FREs.back() =
FRE;
524 FDE.FREs.push_back(FRE);
525 FDE.FREs.back().Label =
L;
532 TotalFREs += FDE.FREs.size();
536 void emitPreamble() {
537 Streamer.emitInt16(
Magic);
538 Streamer.emitInt8(
static_cast<uint8_t
>(Version::V2));
539 Streamer.emitInt8(
static_cast<uint8_t
>(Flags::FDEFuncStartPCRel));
545 Streamer.emitInt8(
static_cast<uint8_t
>(SFrameABI));
547 Streamer.emitInt8(0);
549 Streamer.emitInt8(FixedRAOffset);
551 Streamer.emitInt8(0);
553 Streamer.emitInt32(FDEs.size());
555 Streamer.emitInt32(TotalFREs);
558 Streamer.emitAbsoluteSymbolDiff(FRESubSectionEnd, FRESubSectionStart,
561 Streamer.emitInt32(0);
563 Streamer.emitInt32(FDEs.size() *
564 sizeof(sframe::FuncDescEntry<endianness::native>));
568 Streamer.emitLabel(FDESubSectionStart);
569 for (
auto &FDE : FDEs) {
570 FDE.emit(Streamer, FRESubSectionStart);
575 Streamer.emitLabel(FRESubSectionStart);
576 for (
auto &FDE : FDEs) {
577 Streamer.emitLabel(FDE.FREStart);
578 for (
auto &FRE : FDE.FREs)
579 FRE.emit(Streamer, FDE.DFrame.
Begin, FDE.Frag);
581 Streamer.emitLabel(FRESubSectionEnd);
598 SFrameEmitterImpl
Emitter(Streamer);
603 for (
const auto &DFrame : FrameArray)
606 MCSection *Section = Context.getObjectFileInfo()->getSFrameSection();
608 Section->ensureMinAlignment(
Align(8));
610 MCSymbol *SectionStart = Context.createTempSymbol();
621 if (FDEFrag ==
nullptr) {
629 I.setFREType(FREType::Addr1);
631 I.setFREType(FREType::Addr2);
634 I.setFREType(FREType::Addr4);
636 I.setFDEType(FDEType::PCInc);
647 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 ....
ArrayRef - 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 void emit(MCObjectStreamer &Streamer)
static 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
size - Get the string size.
@ C
The default llvm calling convention, compatible with C.
@ FRE
Reciprocal estimate instructions (unary FP ops).
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.