This is an archive of the discontinued LLVM Phabricator instance.

[SelectionDAG] Pick correct frame index in LowerArguments
ClosedPublic

Authored by bjope on Sep 12 2017, 6:31 AM.

Details

Summary

SelectionDAGISel::LowerArguments is associating arguments
with frame indices (FuncInfo->setArgumentFrameIndex). That
information is later on used by EmitFuncArgumentDbgValue to
create DBG_VALUE instructions that denotes that a variable
can be found on the stack.

I discovered that for our (big endian) out-of-tree target
the association created by SelectionDAGISel::LowerArguments
sometimes is wrong. I've seen this happen when a 64-bit value
is passed on the stack. The argument will occupy two stack
slots (frame index X, and frame index X+1). The fault is
that a call to setArgumentFrameIndex is associating the
64-bit argument with frame index X+1. The effect is that the
debug information (DBG_VALUE) will point at the least significant
part of the arguement on the stack. When printing the
argument in a debugger I will get the wrong value.

I managed to create a test case for PowerPC that seems to
show the same kind of problem.

The bugfix will look at the datalayout, taking endianess into
account when examining a BUILD_PAIR node, assuming that the
least significant part is in the first operand of the BUILD_PAIR.
For big endian targets we should use the frame index from
the second operand, as the most significant part will be stored
at the lower address (using the highest frame index).

I also added an assert that we always pick the operand associated
with the highest frame index in this particular piece of code.

Diff Detail

Repository
rL LLVM

Event Timeline

bjope created this revision.Sep 12 2017, 6:31 AM
aprantl added inline comments.Sep 12 2017, 8:50 AM
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
8802 ↗(On Diff #114819)

Always the highest or does this depend on the direction in which the stack grows?

8811 ↗(On Diff #114819)

can you factor the ternary operator out into the definition of BigEndian?

test/CodeGen/PowerPC/debuginfo-stackarg.ll
1 ↗(On Diff #114819)

can this be further localized by adding stop-after=live-debug-values?

45 ↗(On Diff #114819)

please strip all non-essential attributes (everything in quotes?)

bjope added inline comments.Sep 12 2017, 9:27 AM
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
8802 ↗(On Diff #114819)

Oh wait. I guess the frame indices are numbered "in the same way" even if the stack is growing in the other direction (considering negative/positive frame indices etc). So we probably want to find the lowest FI if the stack grows up.
So the comparison in the assert needs to be based on stack direction. And my comment is confusing at the moment. But I hope the pair will be built in the same way (regarding which part that contains the least/most significant bytes), so the rest should be ok.

rnk added inline comments.Sep 12 2017, 10:53 AM
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
8791–8794 ↗(On Diff #114819)

Is it possible to fix this condition up so that we don't pattern match the frame index before *and* after the getMergeValues? We should be able to look through LoadSDNodes here to check for a FrameIndexSDNode.

test/CodeGen/PowerPC/debuginfo-stackarg.ll
45 ↗(On Diff #114819)

Eventually I'd like to make a pass that "canonicalizes" LLVM IR from clang to strip out all this hyper-target-specific junk (PIC size, wchar_size, regparms, etc). It would also remove the optnone attribute which continues to trip me up when I'm trying to generate "simple" LLVM IR for tests with clang -O0. I have to do clang -O1 -Xclang -disable-llvm-passes, and then I remove the lifetime markers because they are mostly noise for debug info.

bjope added inline comments.Sep 12 2017, 2:02 PM
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
8791–8794 ↗(On Diff #114819)

I need to admit that I do not fully understand all the things going on here, and why the setArgumentFrameIndex calls only are done in different special scenarios.
Some examples:

  • At line 8759 it is done "for use in FastISel" according to the code comment on line 8756.
  • At line 8794 it is done if ArgValues[0] is a FrameIndexSDNode. Is it impossible to end up with ArgValues.size()>1, and also having one of the ArgValues being a FrameIndexSDNode? Or how do we know that it is the FI from ArgValues[0] that should be used in case ArgValues.size()>1?
  • And the scenario below (the one that I have tried to improve) is for the very specific case when ArgValues.size()==1 and ArgValue[0] is a BUILD_PAIR (otherwise Res will end up as ISD::MERGE_VALUES). This scenario is also guarded by an explicit check that FastISel isn't enabled.

That last scenario is also limited since it does not dig deep to find the LoadSDNode/FrameIndexSDNode nodes. I actually think that the getCopyFromParts call (which I believe is creating the BUILD_PAIR) could handle more parts than two. So there could be more values involved and not only a single pair.

So what is the effect of not doing setArgumentFrameIndex? Are we just loosing debug info?

And what is the problem with always calling setArgumentFrameIndex? Is it bad for FastISel in some way?

One idea I had was to examine all InVals (for the interval [i .. i+NumParts-1]) just before the ArgValues.push_back() at line 8779. If any involved part is a FrameIndexSDNode, or a LoasSDNode/FrameIndexSDNode pattern, then I should call setArgumentFrameIndex for the "best" found frame index. If stack grows down then the "best" is the highest index, if stack grows up then the "best" would be the lowest index.
Although, such a solution might seem a little bit hacky. So instead I tried to do a minimal change for the scenario for which I got corrupt debug info in my out-of-tree target.

bjope updated this revision to Diff 115074.Sep 13 2017, 10:54 AM

Some fixes related to comments from Adrian Prantl:

  • Strip some attributes from the test case.
  • Stop test after livedebugvalues (that made it possible to relate checks to positions in the fixedStack instead of load instructions).
  • Reformulated the code comment that did not take stack growth direction into consideration.
  • Removed the assert comparing frame index with for the "other" BUILD_PAIR operand. I think we can live without it, as it got a little bit more complicated when taking stack growth into account.
  • Factored out the "LowAddressOp" number to enhance readability.
bjope marked 5 inline comments as done.Sep 13 2017, 10:56 AM
bjope added inline comments.Sep 13 2017, 11:13 AM
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
8791–8794 ↗(On Diff #114819)

A shorter version of my earlier answer:

  • Yes, the code can probably be refactored.
  • It would be nice to refactor it in some way, because it seems incomplete and hard to understand.

Although, I'm not sure that I feel comfortable with doing such refactoring right now. I've just recently started to dig into how debug-info works in LLVM. Give me a few weeks (or months) and maybe I will be ready for the task. But I would definitely not mind if someone with more experience in this area could dig in to it.

bjope added a comment.Sep 21 2017, 9:29 AM

I'd still like to contribute by landing this bugfix. We are using it for our out-of-tree target and the problem seems to exist for other big-endian targets as well, as shown by the test case for powerpc.
Any objections?
Ping!

Seems ok to me.
@rnk: was your concern addressed?

rnk edited edge metadata.Sep 21 2017, 9:53 AM

Seems ok to me.
@rnk: was your concern addressed?

Yeah, sorry I didn't say anything. My thoughts were along the lines of "yes, this code is complicated and hard to simplify. Bummer. :("

aprantl accepted this revision.Sep 21 2017, 10:07 AM
This revision is now accepted and ready to land.Sep 21 2017, 10:07 AM
This revision was automatically updated to reflect the committed changes.
In D37740#877747, @rnk wrote:

Seems ok to me.
@rnk: was your concern addressed?

Yeah, sorry I didn't say anything. My thoughts were along the lines of "yes, this code is complicated and hard to simplify. Bummer. :("

Thanks for the review! Hopefully we can come back and simplify this code in the future.