This is an archive of the discontinued LLVM Phabricator instance.

X86: balance the frame prologue and epilogue on Win64
ClosedPublic

Authored by compnerd on Jun 14 2021, 11:07 AM.

Details

Summary

This was broken in ba1509da7b89c850c89f0f98afbab375794cd3c8. The Win64
frame would not perform the setup of the Swift async context parameter
but would tear down the setup in the epilogue resulting in crashes.
This ensures that we do the full setup when we do the tear down.
Although this is non-conforming to the Win64 calling convention, it
corrects the setup and exposes the actual issue that the change
introduced: incorrect frame setup.

Diff Detail

Event Timeline

compnerd created this revision.Jun 14 2021, 11:07 AM
compnerd requested review of this revision.Jun 14 2021, 11:07 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 14 2021, 11:07 AM
rnk accepted this revision.Jun 14 2021, 12:04 PM

lgtm

The code change is just adjusting some if conditions and changing indentation, so there's no reason to hold it up with my design questions. Please consider implementing the refactoring suggestion as a follow-up, though.

llvm/lib/Target/X86/X86FrameLowering.cpp
1486

As a style comment, I think this code would be easier to read if it was moved out of line. The emitPrologue/emitEpilog functions are really, really long. Anything you can do to shorten them helps with understanding. If you can pair the swift async context setup and teardown code somewhere later in the file, it would help. The main state going in and out is MBB, MBBI, DL. See BuildStackAlignAND for an example of this.

llvm/test/CodeGen/X86/swift-async-win64.ll
10–11

Maybe I misunderstand, but won't this prevent every existing Windows unwinder, debuggers included, from unwinding the native stack? BTS *sets* bit 60 of RBP before it is pushed. If the caller's frame uses RBP as a frame pointer, how will a Swift-unaware stack unwinder use RBP to continue unwinding? It won't know to clear out bit 60.

Is it really the plan to make it so that you cannot debug Swift code from a Swift-unaware debugger? I'm not sure LLDB on Windows is really ready, so I imagine that folks will want to use windbg to debug Swift code in the near future. This isn't a Windows-specific concern either. Anyone using gdb, rr, perf, and other stack samplers on Linux will have similar issues, right?

This revision is now accepted and ready to land.Jun 14 2021, 12:04 PM
compnerd updated this revision to Diff 352035.Jun 14 2021, 8:05 PM
compnerd added inline comments.Jun 14 2021, 8:23 PM
llvm/lib/Target/X86/X86FrameLowering.cpp
1486

I completely agree with you on this point. I really want to see if I can split out the functions somewhat in follow ups. The reason is that right now the code is really difficult to read as there are the following paths:

  • Win32
    • Funclet
    • Non-Funclet
  • Win64
    • Funclet
    • Non-Funclet
  • Non-Windows

It really feels like this should be three different implementations but I dont fully see how to structure this yet.

llvm/test/CodeGen/X86/swift-async-win64.ll
10–11

Yes, it does break other unwinders AIUI. The bit 60 is the marker that debugger uses to determine if the frame contains an async context (or NULL), which is expected to be the next value after the base pointer.

Swift debugging is already broken entirely with non-lldb debuggers sadly. However, that does does misrepresent the reality that WinDBG is really the debugger of choice currently on Windows. Debugging Swift on Linux already requires LLDB on Linux, and that includes gdb, rr, perf, or any other stack samplers.

This revision was automatically updated to reflect the committed changes.