diff options
Diffstat (limited to 'llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp')
| -rw-r--r-- | llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp | 55 |
1 files changed, 51 insertions, 4 deletions
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp index 093dab4f2f9..bee9b704633 100644 --- a/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp +++ b/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp @@ -38,6 +38,7 @@ public: bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override; bool emitFPOPushReg(unsigned Reg, SMLoc L) override; bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override; + bool emitFPOStackAlign(unsigned Align, SMLoc L) override; bool emitFPOSetFrame(unsigned Reg, SMLoc L) override; }; @@ -47,6 +48,7 @@ struct FPOInstruction { enum Operation { PushReg, StackAlloc, + StackAlign, SetFrame, } Op; unsigned RegOrOffset; @@ -90,6 +92,7 @@ public: bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override; bool emitFPOPushReg(unsigned Reg, SMLoc L) override; bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override; + bool emitFPOStackAlign(unsigned Align, SMLoc L) override; bool emitFPOSetFrame(unsigned Reg, SMLoc L) override; }; } // end namespace @@ -133,6 +136,11 @@ bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc, return false; } +bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlign(unsigned Align, SMLoc L) { + OS << "\t.cv_fpo_stackalign\t" << Align << '\n'; + return false; +} + bool X86WinCOFFAsmTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) { OS << "\t.cv_fpo_setframe\t"; InstPrinter.printRegName(OS, Reg); @@ -226,6 +234,24 @@ bool X86WinCOFFTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) { return false; } +bool X86WinCOFFTargetStreamer::emitFPOStackAlign(unsigned Align, SMLoc L) { + if (checkInFPOPrologue(L)) + return true; + if (!llvm::any_of(CurFPOData->Instructions, [](const FPOInstruction &Inst) { + return Inst.Op == FPOInstruction::SetFrame; + })) { + getContext().reportError( + L, "a frame register must be established before aligning the stack"); + return true; + } + FPOInstruction Inst; + Inst.Label = emitFPOLabel(); + Inst.Op = FPOInstruction::StackAlign; + Inst.RegOrOffset = Align; + CurFPOData->Instructions.push_back(Inst); + return false; +} + bool X86WinCOFFTargetStreamer::emitFPOEndPrologue(SMLoc L) { if (checkInFPOPrologue(L)) return true; @@ -250,6 +276,8 @@ struct FPOStateMachine { unsigned CurOffset = 0; unsigned LocalSize = 0; unsigned SavedRegSize = 0; + unsigned StackOffsetBeforeAlign = 0; + unsigned StackAlign = 0; unsigned Flags = 0; // FIXME: Set HasSEH / HasEH. SmallString<128> FrameFunc; @@ -291,24 +319,39 @@ void FPOStateMachine::emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label) { FrameFunc.clear(); raw_svector_ostream FuncOS(FrameFunc); const MCRegisterInfo *MRI = OS.getContext().getRegisterInfo(); + assert((StackAlign == 0 || FrameReg != 0) && + "cannot align stack without frame reg"); + StringRef CFAVar = StackAlign == 0 ? "$T0" : "$T1"; + if (FrameReg) { // CFA is FrameReg + FrameRegOff. - FuncOS << "$T0 " << printFPOReg(MRI, FrameReg) << " " << FrameRegOff + FuncOS << CFAVar << ' ' << printFPOReg(MRI, FrameReg) << ' ' << FrameRegOff << " + = "; + + // Assign $T0, the VFRAME register, the value of ESP after it is aligned. + // Starting from the CFA, we subtract the size of all pushed registers, and + // align the result. While we don't store any CSRs in this area, $T0 is used + // by S_DEFRANGE_FRAMEPOINTER_REL records to find local variables. + if (StackAlign) { + FuncOS << "$T0 " << CFAVar << ' ' << StackOffsetBeforeAlign << " - " + << StackAlign << " @ = "; + } } else { // The address of return address is ESP + CurOffset, but we use .raSearch to // match MSVC. This seems to ask the debugger to subtract some combination // of LocalSize and SavedRegSize from ESP and grovel around in that memory // to find the address of a plausible return address. - FuncOS << "$T0 .raSearch = "; + FuncOS << CFAVar << " .raSearch = "; } // Caller's $eip should be dereferenced CFA, and $esp should be CFA plus 4. - FuncOS << "$eip $T0 ^ = $esp $T0 4 + = "; + FuncOS << "$eip " << CFAVar << " ^ = "; + FuncOS << "$esp " << CFAVar << " 4 + = "; // Each saved register is stored at an unchanging negative CFA offset. for (RegSaveOffset RO : RegSaveOffsets) - FuncOS << printFPOReg(MRI, RO.Reg) << " $T0 " << RO.Offset << " - ^ = "; + FuncOS << printFPOReg(MRI, RO.Reg) << ' ' << CFAVar << ' ' << RO.Offset + << " - ^ = "; // Add it to the CV string table. CodeViewContext &CVCtx = OS.getContext().getCVContext(); @@ -380,6 +423,10 @@ bool X86WinCOFFTargetStreamer::emitFPOData(const MCSymbol *ProcSym, SMLoc L) { FSM.FrameReg = Inst.RegOrOffset; FSM.FrameRegOff = FSM.CurOffset; break; + case FPOInstruction::StackAlign: + FSM.StackOffsetBeforeAlign = FSM.CurOffset; + FSM.StackAlign = Inst.RegOrOffset; + break; case FPOInstruction::StackAlloc: FSM.CurOffset += Inst.RegOrOffset; FSM.LocalSize += Inst.RegOrOffset; |

