This is an archive of the discontinued LLVM Phabricator instance.

[GlobalISel][Legalizer] Don't use eraseFromParentAndMarkDBGValuesForRemoval() for some artifacts.
ClosedPublic

Authored by aemerson on Sep 14 2021, 2:45 AM.

Details

Summary

For artifacts excluding G_TRUNC/G_SEXT, which have IR counterparts, we don't
seem to have debug users of defs. However, in the legalizer we're always calling
MachineInstr::eraseFromParentAndMarkDBGValuesForRemoval() which is expensive.
In some rare cases, this contributes significantly to unreasonably long compile
times when we have lots of artifact combiner activity.

To verify this, I added asserts to that function when it actually replaced a debug
use operand with undef for these artifacts. On CTMark with both -O0 and -Os and
debug info enabled, I didn't see a single case where it triggered.

In my measurements I saw around a 0.5% geomean compile-time improvement on -g -O0
for AArch64 with this change.

Diff Detail

Event Timeline

aemerson created this revision.Sep 14 2021, 2:45 AM
aemerson requested review of this revision.Sep 14 2021, 2:45 AM
aemerson updated this revision to Diff 372446.Sep 14 2021, 2:49 AM

Fix test.

arsenm added inline comments.Sep 14 2021, 6:00 AM
llvm/lib/CodeGen/GlobalISel/Legalizer.cpp
175 ↗(On Diff #372446)

Don't we already have an isArtifact check somewhere?

arsenm added inline comments.Sep 14 2021, 6:02 AM
llvm/lib/CodeGen/GlobalISel/Legalizer.cpp
175 ↗(On Diff #372446)

Oh, I just reread and this is different. Can you add a comment justifying why these operations are skipped?

Maybe should add a verifier check that these never have dbg users

llvm/test/CodeGen/AMDGPU/GlobalISel/bug-legalization-artifact-combiner-dead-def.mir
87

This is now broken, dbg_use has no def. Maybe delete this test since it was artificial to begin with. Relevant tests are above.

Maybe should add a verifier check that these never have dbg users

I don't think we should go that far. If we do have a debug user then not marking the use as undef AFAICT isn't strictly incorrect.

aemerson updated this revision to Diff 372817.Sep 15 2021, 3:23 PM
aemerson updated this revision to Diff 372819.Sep 15 2021, 3:27 PM

Add comment.

arsenm added inline comments.Sep 15 2021, 3:28 PM
llvm/lib/CodeGen/GlobalISel/Legalizer.cpp
185 ↗(On Diff #372817)

Should still get a comment explaining why these operations

aemerson added inline comments.Sep 15 2021, 3:30 PM
llvm/lib/CodeGen/GlobalISel/Legalizer.cpp
185 ↗(On Diff #372817)

I updated very shortly before your reply. Is this comment ok?

foad added a comment.Sep 20 2021, 5:02 AM

Needs rebasing (maybe re-benchmarking too?) after D109154.

Needs rebasing (maybe re-benchmarking too?) after D109154.

I think this is orthogonal to D109154 so don't need to rebenchmark.

paquette added inline comments.Sep 20 2021, 4:56 PM
llvm/lib/CodeGen/GlobalISel/Utils.cpp
1060

might as well pull the return false; into the default case?

aemerson updated this revision to Diff 373750.Sep 20 2021, 5:02 PM
arsenm accepted this revision.Sep 20 2021, 5:02 PM
arsenm added inline comments.
llvm/lib/CodeGen/GlobalISel/Utils.cpp
1060

I think the only combination that stops warnings on all compilers is return false in the default case with an llvm_unreachable after the switch

This revision is now accepted and ready to land.Sep 20 2021, 5:02 PM
This revision was landed with ongoing or failed builds.Sep 20 2021, 11:34 PM
This revision was automatically updated to reflect the committed changes.
dsanders added inline comments.
llvm/lib/CodeGen/GlobalISel/Utils.cpp
1054–1058

I don't think this assumption holds beyond the first time the legalizer processes each instruction and is dubious earlier than that if you have pre-legalization passes too.

For the standard pipeline of passes, suppose you have an expansion in the legalizer that replaces some operation with a DBG_VALUE with something ending in G_MERGE_VALUES (or one of the others). On the next legalization step you have a G_MERGE_VALUES with a DBG_VALUE. That already breaks the assumption it doesn't have one but it takes a bit more to go wrong. If anything causes this G_MERGE_VALUES to be deleted without replacement you are left with a use-without-def as the DBG_VALUE is not erased. For example, if this is one lane of a bigger G_UNMERGE_VALUES/G_MERGE_VALUES pair and something proves the lane isn't needed it would erase all the instructions for the lane but leave the DBG_VALUE behind.

I haven't dug into it myself but I'm told we've run into this scenario in our downstream target and we've had to revert this change.

jackoalan added inline comments.
llvm/lib/CodeGen/GlobalISel/Utils.cpp
1054–1058

I'd like to echo this claim. It is far too presumptuous to assume artifacts like G_MERGE_VALUES are never created pre-legalizer for all targets. If anything, this decision should be made per-target in LegalizerInfo.

jackoalan added inline comments.Oct 17 2021, 1:56 PM
llvm/lib/CodeGen/GlobalISel/Utils.cpp
1054–1058

I found a specific case where GlobalISel's IRTranslator emits G_MERGE_VALUES: Lowering a call with arguments that are wider than native machine types. I think G_UNMERGE_VALUES, G_MERGE_VALUES, G_CONCAT_VECTORS, G_BUILD_VECTOR should be excluded from this test because they are all reachable in CallLowering and therefore originate from IR.