[llvm-dev] llvm combines "ADD frameindex, constant" to OR

Tim Northover via llvm-dev llvm-dev at lists.llvm.org
Wed Mar 13 03:09:14 PDT 2019


Hi,

On Wed, 13 Mar 2019 at 00:25, Kazushi Marukawa via llvm-dev
<llvm-dev at lists.llvm.org> wrote:
>
> Hi all,
>
> I've been working on a backend of our architecture and noticed llvm performs
> following combining although one of operands is FrameIndex.
>
>     Combining: t114: i64 = add FrameIndex:i64<0>, Constant:i64<56>
>     Creating new node: t121: i64 = or FrameIndex:i64<0>, Constant:i64<56>
>      ... into: t121: i64 = or FrameIndex:i64<0>, Constant:i64<56>
>
> This caused problem if frame pointer points 0x60000038 at run time.
>
>
> I checked DAGCombiner::visitADD.  It folds ADD to OR by following code
> without considering about FrameIndex.  This haveNoCommonBitsSet says
> it's safe since FrameIndex(0) is 0.

This sounds like your fundamental problem to me. The generic code path
is computeKnownBits -> computeKnownBitsForFrameIndex ->
InferPtrAlignment. If your stack slot can legitimately end up at an
offset only aligned to 0x8 then that's going wrong somewhere and you
should probably work out why.

I don't really have the details to say for sure, but unless you've
overridden computeKnownBitsForFrameIndex a reasonably likely scenario
is that the alloca for that local variable requested 16-bit alignment
but your sp itself is only routinely aligned to 8 bytes (or less) and
you actually need to realign sp manually in XYZFrameLowering to
support that variable.

The ISD::OR thing can be annoying, but shouldn't affect correctness.

>         // Undo the add -> or combine to merge constant offsets from a frame index.
>         if (N0.getOpcode() == ISD::OR &&
>             isa<FrameIndexSDNode>(N0.getOperand(0)) &&
>             isa<ConstantSDNode>(N0.getOperand(1)) &&
>             DAG.haveNoCommonBitsSet(N0.getOperand(0), N0.getOperand(1))) {
>           SDValue Add0 = DAG.getNode(ISD::ADD, DL, VT, N1, N0.getOperand(1));
>           return DAG.getNode(ISD::ADD, DL, VT, N0.getOperand(0), Add0);
>         }
>
> I think this code may work fine on an architecture using FI + A + B.

It's target independent, and again shouldn't affect correctness. The
entire transformation is (FI | A) + B -> (FI + (A+B)). Useful when it
triggers, but not much else.

>   1. Is there any way to control this to avoid OR folding,
>      like TargetLowering::preferNotCombineToOrFrameIndex?
>      (or should we add new?)

There isn't as far as I know. I've heard it justified as
canonicalization before, and not been entirely convinced myself. But
it's generally pretty easy to cope with in the backend because
SelectionDAG::isBaseWithConstantOffset  deals with it correctly.

>   2. How to optimize FrameIndex?  I desire DAGCombiner use alignment
>      information on data, stack frame, or something.

As I said above, I think it should already use that and something has
gone wrong there in your case.

Cheers.

Tim.


More information about the llvm-dev mailing list