This is an archive of the discontinued LLVM Phabricator instance.

bug fix for PR20020: anti-dependency-breaker causes miscompilation
ClosedPublic

Authored by spatel on Jun 30 2014, 2:56 PM.

Details

Summary

This patch sets the 'KeepReg' bit for any tied registers during the PrescanInstruction() phase of the dependency breaking algorithm. It then checks those 'KeepReg' bits during the ScanInstruction() phase to avoid changing any tied registers. For more details, please see comments in:
http://llvm.org/bugs/show_bug.cgi?id=20020

The existing code also uses the 'Classes' variable as a marker for registers that shouldn't be changed (by setting the value to -1). If someone can explain why we need two data structures to mark unusable regs, I'd love to understand that.

I added two FIXME comments for code that I think can be removed by using register iterators that include self. I don't want to include those code changes with this patch, however, to keep things as small as possible.

The test case is larger than I'd like, but I don't know how to reduce it further and still produce the failing asm.

Diff Detail

Repository
rL LLVM

Event Timeline

spatel updated this revision to Diff 10985.Jun 30 2014, 2:56 PM
spatel retitled this revision from to bug fix for PR20020: anti-dependency-breaker causes miscompilation.
spatel updated this object.
spatel edited the test plan for this revision. (Show Details)
spatel added reviewers: hfinkel, atrick.
spatel added a subscriber: Unknown Object (MLST).
hfinkel edited edge metadata.Jun 30 2014, 3:12 PM

Can you please upload the patch with more context lines (as explained here: http://llvm.org/docs/Phabricator.html)?

lib/CodeGen/CriticalAntiDepBreaker.cpp
260 ↗(On Diff #10985)

Can you put an assert inside the existing check that the tied registers are in KeepRegs?

spatel added inline comments.Jun 30 2014, 3:27 PM
lib/CodeGen/CriticalAntiDepBreaker.cpp
260 ↗(On Diff #10985)

Do you mean:
if (MI->isRegTiedToUseOperand(i)) {
assert(KeepRegs.test(Reg) && "Register is tied but was not added to KeepRegs"));
continue;
}

But we're checking the KeepRegs value just above this and continuing at that point in the code, so this would only fire if someone inadvertently put code between these two 'if' checks?

hfinkel added inline comments.Jun 30 2014, 3:35 PM
lib/CodeGen/CriticalAntiDepBreaker.cpp
260 ↗(On Diff #10985)

No, I mean replacing that with the assert (since PreScan should have caught them all). So instead of:

if (MI->isRegTiedToUseOperand(i)) continue;

We'd have:

assert(!MI->isRegTiedToUseOperand(i) && "Tied operand not in KeepRegs?");

spatel updated this revision to Diff 10988.Jun 30 2014, 5:20 PM
spatel edited edge metadata.

Thanks, Hal! Updated with assert() and full diff.

But I now see that this change breaks test/Codegen/X86/atom-sched.ll because that test implicitly enabled -break-anti-dependencies. I'll have to investigate.

spatel updated this revision to Diff 11034.Jul 2 2014, 2:11 PM

Updated patch to only set KeepRegs[reg] when a reg is tied AND live. This allows the existing Atom test case to work as expected.
This patch should make the code strictly safer (do less work) and avoid PR20020 while preserving all existing regression test behavior.

I removed the assert() that was in the previous draft because there is one existing test (test/Codegen/X86/select.ll - test17) where it would still fire. This is because that test has an instruction with a tied op, but we don't set KeepRegs for it because we only change the Classes[] value for the reg after-the-fact based on a register that aliases it around this code:

// If an alias of the reg is used during the live range, give up.

LGTM; thanks!

test/CodeGen/X86/pr20020.ll
73 ↗(On Diff #11034)

Please remove any unneeded attributes.

spatel closed this revision.Jul 3 2014, 8:28 AM
spatel updated this revision to Diff 11055.

Closed by commit rL212275 (authored by @spatel).

danilaml added inline comments.
llvm/trunk/lib/CodeGen/CriticalAntiDepBreaker.cpp
203

@spatel Hi, I was debugging some miscompile issue and came across what I think is very similar bug.
Do you remember why you check against -1 here? In my test-case (which I'm trying to reduce), the Classes[Reg] is some regclass non -1 value. According to the comments for Classes:

/// For live regs that are only used in one register class in a
    /// live range, the register class. If the register is not live, the
    /// corresponding value is null. If the register is live but used in
    /// multiple register classes, the corresponding value is -1 casted to a
    /// pointer.

My question is: why is this code is checking for -1 specifically, instead of != nullptr? If it's not live, would it still be OK? I have trouble following the logic in this pass.
The comments for scan indicate that

// Note: AntiDepReg may be referenced by a two-address instruction such that
// it's use operand is tied to a def operand ...
// In this case, both the use and def operands are in
// RegRefs because the def is inserted by PrescanInstruction and not erased
// during ScanInstruction.

which is evidently not true in my test case (e.g. XOR has 3 same-reg operands, one pair tied, so the ScanInstruction would remove all RegRefs added by Prescan due to the 3rd non-tied reg, and skip the first tied def when adding refs back).

Herald added a project: Restricted Project. · View Herald TranscriptAug 3 2021, 7:26 AM
spatel added inline comments.Aug 10 2021, 3:53 AM
llvm/trunk/lib/CodeGen/CriticalAntiDepBreaker.cpp
203

Wow - I barely remember creating this patch. I haven't looked at anything near here in so long, that I can't offer much help. I see that you posted D107582 - let's see if we can find someone more knowledgeable to review.