This is an archive of the discontinued LLVM Phabricator instance.

[InstCombine] fold gep-of-select-of-constants (PR45084)
ClosedPublic

Authored by spatel on Mar 7 2020, 7:28 AM.

Details

Summary

As shown in PR45084:
https://bugs.llvm.org/show_bug.cgi?id=45084
...we failed to combine a gep with constant indexes with a pointer operand that is a select of constants.

Diff Detail

Event Timeline

spatel created this revision.Mar 7 2020, 7:28 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 7 2020, 7:28 AM
nikic added inline comments.Mar 7 2020, 9:28 AM
llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
1816

Should the select be limited to one use? I'm not sure whether this transform is favorable if we need to keep both selects. In either case, this should be tested.

1822

It is better to construct these GEPs via IRBuilder, so the resulting constants get folded right away (GEPs are target-dependent).

Also, aren't we losing inbounds here?

1823

We can preserve branch weight metadata here.

spatel marked 6 inline comments as done.Mar 8 2020, 8:42 AM
spatel added inline comments.
llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
1816

Unless there's evidence that the select-of-constants form is less favorable, we want to allow the transform because it eliminates a use of the existing select. I'll add a test.

1822

Can you describe the benefit of IRBuilder vs. ConstantExpr::get()? I'm not seeing any difference in the debug output for the examples that I have.

I'm happy to change it (but we should probably change a bunch of existing similar code too?).

I'm not clear on the inbounds rules here (it's a constant, so is it not required to be inbounds?). But yes, I'll fix this to inherit from the existing instruction.

1823

Yes, good catch - I'll add to the test.

spatel updated this revision to Diff 248997.Mar 8 2020, 8:44 AM
spatel marked 3 inline comments as done.

Patch updated:

  1. Propagate metadata from select (test adjusted).
  2. Propagate 'inbounds' from gep (not sure how to test non-inbounds case).
  3. Added test for >1 use of the select.
nikic added inline comments.Mar 8 2020, 10:37 AM
llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
1822

Can you describe the benefit of IRBuilder vs. ConstantExpr::get()? I'm not seeing any difference in the debug output for the examples that I have.

Sure. Take something like

%struct.f = type { i32, i32 }
  
@g0 = internal unnamed_addr constant %struct.f zeroinitializer, align 4

define i32* @PR45084(i1 %cond) {
  %sel = select i1 %cond, %struct.f* @g0, %struct.f* null
  %gep = getelementptr inbounds %struct.f, %struct.f* %sel, i64 0, i32 1
  ret i32* %gep
}

In the log we see:

IC: Old =   %gep = getelementptr inbounds %struct.f, %struct.f* %sel, i64 0, i32 1
    New =   <badref> = select i1 %cond, i32* getelementptr inbounds (%struct.f, %struct.f* @g0, i64 0, i32 1), i32* getelementptr inbounds (%struct.f, %struct.f* null, i64 0, i32 1)
...
IC: ConstFold operand of:   %gep = select i1 %cond, i32* getelementptr inbounds (%struct.f, %struct.f* @g0, i64 0, i32 1), i32* getelementptr inbounds (%struct.f, %struct.f* null, i64 0, i32 1)
    Old = i32* getelementptr inbounds (%struct.f, %struct.f* null, i64 0, i32 1)
    New = i32* inttoptr (i64 4 to i32*)

This is a target-depending fold, so it is not performed during ConstantExpr construction. It will be automatically performed if you go through IRBuilder, and save the need to do this on the next IC iteration.

I'm happy to change it (but we should probably change a bunch of existing similar code too?).

Existing code seems to get this mostly right, though I did fix one occurrence in 9b5de84e274fe9df971e5d32cc4ffe1ab972519d.

I'm not clear on the inbounds rules here (it's a constant, so is it not required to be inbounds?). But yes, I'll fix this to inherit from the existing instruction.

If that were the case, I would assume that the inbounds flag wouldn't exist on ConstantExpr GEP in the first place. I think it's fine to have non-inbounds GEP on constants. E.g. my example above is wrong, the GEP on null can't be inbounds. I don't know if any of the ConstantExpr actually optimizes on inbounds though, I didn't find anything from a quick search.

spatel updated this revision to Diff 249071.Mar 9 2020, 5:46 AM
spatel marked an inline comment as done.

Patch updated:
Use IRBuilder to efficiently create the GEP constant expressions.

nikic accepted this revision.Mar 9 2020, 1:36 PM

LGTM

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
1829

Surprised that IRBuilder has no overloads accepting bool...

This revision is now accepted and ready to land.Mar 9 2020, 1:36 PM
This revision was automatically updated to reflect the committed changes.