This is an archive of the discontinued LLVM Phabricator instance.

[SystemZ] Save/restore r6 and r7 if function contains landing pad.
ClosedPublic

Authored by koriakin on Mar 29 2016, 1:32 AM.

Diff Detail

Repository
rL LLVM

Event Timeline

koriakin retitled this revision from to [SystemZ] Save/restore r6 and r7 if function contains landing pad..
koriakin updated this object.
koriakin added a reviewer: uweigand.
koriakin set the repository for this revision to rL LLVM.
uweigand edited edge metadata.Mar 29 2016, 10:09 AM

It would be better to get the register numbers via the existing TargetLowering hooks getExceptionPointerRegister and getExceptionSelectorRegister.

This way, it might be possible to move the code to the common code base implementation of determineCalleeSaves in CodeGen/TargetFrameLoweringImpl.cpp.

B.t.w. I'm wondering why this doesn't already work, since common code already knows about those registers and marks them as live-in to the landing pad basic blocks:

BB#2: derived from LLVM BB %lpad, EH LANDING PAD
    Live Ins: %R6D %R7D %R11D
    Predecessors according to CFG: BB#0
        EH_LABEL <MCSym=.Ltmp2>
        STG %R6D<kill>, %R11D, 176, %noreg; mem:ST8[%exn.slot]
        %R0L<def> = COPY %R7L, %R7D<imp-use,kill>
        ST %R0L<kill>, %R11D, 172, %noreg; mem:ST4[%ehselector.slot]
        J <BB#3>

For some reason, this doesn't seem to be enough to consider those registers modified by the MRI.isPhysRegModified hook called from the common code determineCalleeSaves implementation ...

koriakin planned changes to this revision.Apr 8 2016, 2:30 AM
koriakin retitled this revision from [SystemZ] Save/restore r6 and r7 if function contains landing pad. to [CodeGen] Consider register modified if it's used to pass landing pad parameters..
koriakin updated this object.
koriakin edited edge metadata.
koriakin added a subscriber: llvm-commits.

As far as I can see, the getPersonalities call here operates on a per-module basis, i.e. it returns all personalities used by any function in the current module, not just the current function. If other functions in the module use exceptions, but not this one, this may lead to overindication here. Not sure if that is a problem in practice ...

In any case, since this is now no longer a SystemZ specific fix, it would probably be better to add reviewers more familiar with this part of common code.

koriakin planned changes to this revision.May 1 2016, 1:17 PM

As far as I can see, the getPersonalities call here operates on a per-module basis, i.e. it returns all personalities used by any function in the current module, not just the current function. If other functions in the module use exceptions, but not this one, this may lead to overindication here. Not sure if that is a problem in practice ...

That was a bad thinko...

MatzeB requested changes to this revision.May 2 2016, 12:32 PM
MatzeB edited edge metadata.

I think you should rather change the TargetFrameLowering::determineCalleeSaves() callback of the target to mark the registers as callee saved.

If this really makes sense for all targets then it could also be done in the PrologEpilogueInsertion code before/after determineCalleeSaves(), but I am not convinced yet this applies universally (though I'm no expert in exception handling code).

This revision now requires changes to proceed.May 2 2016, 12:32 PM

I think you should rather change the TargetFrameLowering::determineCalleeSaves() callback of the target to mark the registers as callee saved.

If this really makes sense for all targets then it could also be done in the PrologEpilogueInsertion code before/after determineCalleeSaves(), but I am not convinced yet this applies universally (though I'm no expert in exception handling code).

Well, this applies to any target whose exception pointer/selector registers are callee-save. I'm not sure if there's any target other than SystemZ where that applies for the default calling convention. However, it can apply to other targets as well if you have a landing pad in a function with eg. preserve_mostcc calling convention - is that supposed to work?

I think you should rather change the TargetFrameLowering::determineCalleeSaves() callback of the target to mark the registers as callee saved.

If this really makes sense for all targets then it could also be done in the PrologEpilogueInsertion code before/after determineCalleeSaves(), but I am not convinced yet this applies universally (though I'm no expert in exception handling code).

Well, this applies to any target whose exception pointer/selector registers are callee-save. I'm not sure if there's any target other than SystemZ where that applies for the default calling convention. However, it can apply to other targets as well if you have a landing pad in a function with eg. preserve_mostcc calling convention - is that supposed to work?

So I've been thinking about this a bit more. We actually have a similar concept already in MachineBasicBlock::getBeginClobberMask() and MachineBasicBlock::getEndClobberMask() that gives you the set of registers clobbered between basic blocks which is exactly used to describe the clobbering effects of the personality function.

My first intuition would be that we just need to provide the proper clobber mask for all personality functions to get your desired behavior. However currently this would not help because these extra clobber masks are not passed to MachineRegisterInfo::addPhysRegsUsedFromRegMask() in the VirtRegRewriter and thus are not considered for prologue epilogue insertion.

Do we actually generate a proper epilogue when we leave the function via an exception? Maybe that is not the case for WinEH which would already be an example against these clobbers needing to be unconditionally spilled/restored...

+CC Reid, David who may have more insight into exception handling ABIs...

This was no accident, I very carefully arranged to represent these masks as something other than MachineOperands specifically so that PEI *wouldn't* consider them clobbered. :)

On Win64, the unwinder arranges to restore all your registers to what they were at the point of the throwing call site, either after you rejoin normal control flow (via catchret in LLVM) or by unwinding out of the frame. They *don't* restore the registers on entry into a funclet cleanuppad or catchpad, which is why we have these register masks in in the first place. Win64 has *many* CSRs including XMM registers, so if things were not arranged this way, all functions using WinEH would have ridiculously large prologues.

While in principle this is rather a problem for shrink wrapping and not announcing the clobber to MRI::addPhysRegsUsedMask() is wrong. I can see that in practice we are simply not there yet.

So it seems to me like the best action today would be to leave the decision of what registers modified by the personality function should be saved/restored to the target in TargetFrameLowering::determineCalleeSaves(), and maybe provide a shared implementation of this bit to avoid code duplication...

This was no accident, I very carefully arranged to represent these masks as something other than MachineOperands specifically so that PEI *wouldn't* consider them clobbered. :)

On Win64, the unwinder arranges to restore all your registers to what they were at the point of the throwing call site, either after you rejoin normal control flow (via catchret in LLVM) or by unwinding out of the frame. They *don't* restore the registers on entry into a funclet cleanuppad or catchpad, which is why we have these register masks in in the first place. Win64 has *many* CSRs including XMM registers, so if things were not arranged this way, all functions using WinEH would have ridiculously large prologues.

While in principle this is rather a problem for shrink wrapping and not announcing the clobber to MRI::addPhysRegsUsedMask() is wrong. I can see that in practice we are simply not there yet.

So it seems to me like the best action today would be to leave the decision of what registers modified by the personality function should be saved/restored to the target in TargetFrameLowering::determineCalleeSaves(), and maybe provide a shared implementation of this bit to avoid code duplication...

Well, my first diff was like that (I forgot to add context, but the implementation is indeed in SystemZTargetFrameLowering::determineCalleeSaves()), so I'm fine with that.

But, how about keeping this target-independent, and making it depend on personality function kind instead? AFAICS the underlying issue also affects x86_64-linux with coldcc - do we want to support this?

koriakin retitled this revision from [CodeGen] Consider register modified if it's used to pass landing pad parameters. to [SystemZ] Save/restore r6 and r7 if function contains landing pad..
koriakin updated this object.
koriakin edited edge metadata.

Back to original version (SystemZ only).

uweigand accepted this revision.Jun 27 2016, 6:25 AM
uweigand edited edge metadata.

Well, if there's no simple way to do it in common code, then I guess I'm fine with the back-end patch.

LGTM.

This revision was automatically updated to reflect the committed changes.