This is an archive of the discontinued LLVM Phabricator instance.

[WinEH] Find root frame correctly in CLR funclets
ClosedPublic

Authored by JosephTremoulet on Nov 12 2015, 6:58 AM.

Details

Summary

The value that the CoreCLR personality passes to a funclet for the
establisher frame may be the root function's frame or may be the parent
funclet's (mostly empty) frame in the case of nested funclets. Each
funclet stores a pointer to the root frame in its own (mostly empty)
frame, as does the root function itself. All frames allocate this slot at
the same offset, measured from the post-prolog stack pointer, so that the
same sequence can accept any ancestor as an establisher frame parameter
value, and so that a single offset can be reported to the GC, which also
looks at this slot.

This change allocate the slot when processing function entry, and records
its frame index on the WinEHFuncInfo object, then inserts the code to
set/copy it during prolog emission.

Diff Detail

Event Timeline

JosephTremoulet retitled this revision from to [WinEH] Find root frame correctly in CLR funclets.
JosephTremoulet updated this object.
JosephTremoulet added a subscriber: llvm-commits.
lib/Target/X86/X86FrameLowering.cpp
1206–1213

Do I need to do anything additional here to capture appropriate dataflow constraints? The MachineInstrs this generates dump as:

	MOV64rm %RCX, %RCX, 1, %noreg, 40, %noreg
	MOV64mr %RSP, 1, %noreg, 40, %noreg, %RCX

and I don't know if I need to be marking rsp as a kill, doing something to get it to show up as a LHS, etc.

1281–1283

Similarly, this begets

	MOV64mr %RSP, 1, %noreg, 40, %noreg, %RSP

and I'm wondering if the store needs to be marked volatile like C++'s UnwindHelp store is, etc.

rnk accepted this revision.Nov 12 2015, 11:40 AM
rnk edited edge metadata.

lgtm

lib/Target/X86/X86FrameLowering.cpp
1206–1213

I think you want to say this for the load into RCX:

addRegOffset(
          BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64rm), Establisher),
          Establisher, false, PSPSlotOffset);

Using that overload of BuildMI marks it as a def of RCX, which the MachineVerifier cares about.

1281–1283

I think David was being extra careful by adding volatile. I think he was concerned that backend pass might remove it as it's a store to a stack object that isn't used anywhere else. I'm not convinced it's necessary once we've done prologue insertion after register allocation, but it can't hurt.

1414

I think this can work, you just need to tweak PEI::calculateFrameObjectOffsets() in a subsequent change.

This revision is now accepted and ready to land.Nov 12 2015, 11:40 AM
JosephTremoulet edited edge metadata.
  • Include -verify-machineinstrs in test
  • Annotate rcx def correctly
  • Add missing live-in annotation for establisher
  • Add MachineMemoryOperands for loads/stores
lib/Target/X86/X86FrameLowering.cpp
1206–1213

Great, thanks for the pointer. I added -verify-machineinstrs to the test RUN line, and did need to update this just as you suggested, also was missing the live-in annotation for the parameter. I added the load and store as MachineMemoryOperands as well to be safe, so now the MIR looks like this:

	%RCX<def> = MOV64rm %RCX, 1, %noreg, 40, %noreg; mem:LD8[<unknown>]
	MOV64mr %RSP, 1, %noreg, 40, %noreg, %RCX; mem:Volatile ST8[<unknown>]
1281–1283

Updated as above, now getting

	MOV64mr %RSP, 1, %noreg, 40, %noreg, %RSP; mem:Volatile ST8[FixedStack0]

Adding volatile seemed right since the GC/unwinder may be looking at this, and since the loads in the funclets aren't annotated with the frame index.

1414

I don't understand what I'd need to tweak. Do you mean so that funclets can access their copy of the PSPSym? I'm generating those accesses directly in the prolog emission (the only references are in the prolog), so they aren't using the offset of the frame object -- that object only describes the PSPSym slot in the root function's frame. Or did you mean to optimize frame size by allocating the PSPSym towards the bottom of the frame? Or something else entirely?

rnk added inline comments.Nov 12 2015, 1:51 PM
lib/Target/X86/X86FrameLowering.cpp
1414

I was mostly responding to the TODO below. You could do something similar to this register scavenging code to ensure that UsedSize is typically small:

// Make sure the special register scavenging spill slot is closest to the
// stack pointer.
if (RS && !EarlyScavengingSlots) {
  SmallVector<int, 2> SFIs;
  RS->getScavengingFrameIndices(SFIs);
  for (SmallVectorImpl<int>::iterator I = SFIs.begin(),
         IE = SFIs.end(); I != IE; ++I)
    AdjustStackOffset(MFI, *I, StackGrowsDown, Offset, MaxAlign, Skew);
}
lib/Target/X86/X86FrameLowering.cpp
1414

Ah, got it. Yes, something along those lines would be great. I'm not sure if it's cool to directly teach calculateFrameObjectOffsets special knowledge about the PEI slot or if it would be better to have some "allocate me low" annotation, and if it's "allocate me low" I don't know if it would make sense to fold scavenger handling into that.. also not sure if maybe scavenger considerations need to "trump" PSP considerations, and then does that mean there are different strengths of "allocate me low". In fact for a while I was considering trying to change things to allow createFixedObject to do its "fixing" relative to another base like the top of the outgoing argument area (but then that wouldn't allow trumping the scavengers and what about targets that don't pre-allocate the outgoing argument area)... anyway, yes, happy to separate that as an optimization problem and tackle it in the future :).