This is an archive of the discontinued LLVM Phabricator instance.

[RISCV] Use two ADDIs to do some stack pointer adjustments.
ClosedPublic

Authored by craig.topper on May 25 2022, 9:54 AM.

Details

Summary

If the adjustment doesn't fit in 12 bits, try to break it into
two 12 bit values before falling back to movImm+add/sub.

This is based on a similar idea from isel.

Diff Detail

Event Timeline

craig.topper created this revision.May 25 2022, 9:54 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 25 2022, 9:54 AM
craig.topper requested review of this revision.May 25 2022, 9:54 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 25 2022, 9:54 AM
jrtc27 added a comment.EditedMay 25 2022, 10:08 AM

Doesn't this run the risk of temporarily misaligning the stack (e.g. for Val == 2064)? The psABI says using such a non-standard ABI within a function is fine and that kernels should realign stacks before calling signal handlers. Both FreeBSD and Linux correctly do this for signal handlers so as to not make assumptions about whether userspace is following the standard ABI, but both assume that the kernel itself is following the standard ABI, and so do not realign the stack in their exception entry points, causing the stack to be misaligned if an interrupt is taken in between. Whether this is a bug or not in the kernels is debatable, but with a more careful splitting of Val it should be possible to avoid anyway, with the exception of 4080?

For reference, this is the exact text in the psABI spec:

In the standard ABI, the stack pointer must remain aligned throughout procedure execution. Non-standard ABI code must realign the stack pointer prior to invoking standard ABI procedures. The operating system must realign the stack pointer prior to invoking a signal handler; hence, POSIX signal handlers need not realign the stack pointer. In systems that service interrupts using the interruptee’s stack, the interrupt service routine must realign the stack pointer if linked with any code that uses a non-standard stack-alignment discipline, but need not realign the stack pointer if all code adheres to the standard ABI.

craig.topper planned changes to this revision.May 25 2022, 11:40 AM

Doesn't this run the risk of temporarily misaligning the stack (e.g. for Val == 2064)? The psABI says using such a non-standard ABI within a function is fine and that kernels should realign stacks before calling signal handlers. Both FreeBSD and Linux correctly do this for signal handlers so as to not make assumptions about whether userspace is following the standard ABI, but both assume that the kernel itself is following the standard ABI, and so do not realign the stack in their exception entry points, causing the stack to be misaligned if an interrupt is taken in between. Whether this is a bug or not in the kernels is debatable, but with a more careful splitting of Val it should be possible to avoid anyway, with the exception of 4080?

Good point. I copied the split from what we do in isel without thinking about it. I'll try a better split.

craig.topper updated this revision to Diff 432101.EditedMay 25 2022, 1:12 PM

Instead of dividing in half, use a large immediate, either -2048 or (2048-stackalign),
to do a first adjustment. Then a smaller adjustment for the remainder.

reames added inline comments.May 25 2022, 1:38 PM
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
309–320

Is there anything here that guarantees stack alignment must be smaller than 12 bits? If not, I don't think your statement about -2048 always being aligned holds.

On the positive vs negative direction, shouldn't we always be able to use the same constant by simply swapping the ADD for a SUB?

craig.topper added inline comments.May 25 2022, 2:03 PM
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
309–320

As far as I know the stack align is part of the RISCVFrameLowering constructor. It doesn’t change per function. Unless someone changes it from 16 to a huge value it should be true.

There is no SUBI instruction.

jrtc27 added inline comments.May 25 2022, 5:38 PM
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
321
llvm/test/CodeGen/RISCV/rvv/emergency-slot.mir
157

... which shows up here

llvm/test/CodeGen/RISCV/rvv/large-rvv-stack-size.mir
36

... and here

craig.topper added inline comments.May 25 2022, 7:48 PM
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
321

Thanks I started over forgot to change it after I copy/pasted. I had it right in the first patch.

Use DestReg as the source for the second operation.

This may break assumptions that some unwinding code uses (e.g. an kernel backtrace without debug info). But then again I don't know if any of them handle non-immediate offsets anyway.

This may break assumptions that some unwinding code uses (e.g. an kernel backtrace without debug info). But then again I don't know if any of them handle non-immediate offsets anyway.

What do you mean? Unwinding with neither the frame pointer nor CFI?

llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
315

Nit: MaxAdj -> MaxAdjStep

This may break assumptions that some unwinding code uses (e.g. an kernel backtrace without debug info). But then again I don't know if any of them handle non-immediate offsets anyway.

What do you mean? Unwinding with neither the frame pointer nor CFI?

Yeah I've seen such implementations for MIPS, maybe there are some for RISC-V too. This was not meant as a request to change anything, no one should rely on specific code generation patterns unless it's mandated by a specification.

reames accepted this revision.May 27 2022, 8:43 AM

LGTM.

Minor optional comment from me, and remember to address nit from previous reviewer before landing.

llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
309–320

I'd vague remembered there being more to the stack alignment on x86, and went and glanced. That's specific to the "stackrealign" attribute which we don't appear to support on RISC-V. I'm fine leaving that is for now.

Do me a favor and add the assert that stack align is a reasonable value w.r.t. your chosen constant for future proofing this?

This revision is now accepted and ready to land.May 27 2022, 8:43 AM

Minor improvement noted after LGTM. Feel free to roll into approved patch if you agree with my comment.

llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
315

Hm, I think you can do slightly better here.

2048 is an 11 bit value. This makes sense as you need the high bit to be zero (since immediates are sign extended).

However, since you're subtracting off a non-zero value, I think you can actually use 4096 as your starting value. That *isn't* representable as a positive 12 bit value, but every value *less than* that is.

reames added inline comments.May 27 2022, 8:52 AM
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
315

Ignore this. I managed to misread my hex values. 2048 is correct here in exactly the way I was suggesting for 4096.

craig.topper added inline comments.May 27 2022, 8:56 AM
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
315

Maybe I should mention that this line was taken directly from RISCVFrameLowering::getFirstSPAdjustAmount.

Rename variable. Cleanup comment slightly.

This revision was landed with ongoing or failed builds.May 31 2022, 10:25 AM
This revision was automatically updated to reflect the committed changes.