Page MenuHomePhabricator

[ARM] Fix bug in ARMLoadStoreOptimizer when kill flags are missing.
ClosedPublic

Authored by gberry on Aug 25 2017, 1:49 PM.

Details

Summary

ARMLoadStoreOpt::FixInvalidRegPairOp() was only checking if one of the
load destination registers to be split overlapped with the base register
if the base register was marked as killed. Since kill flags may not
always be present, this can lead to incorrect code.

This bug was exposed by my MachineCopyPropagation change D30751 breaking
the sanitizer-x86_64-linux-android buildbot.

Diff Detail

Repository
rL LLVM

Event Timeline

gberry created this revision.Aug 25 2017, 1:49 PM

If I understand correctly, the original code was checking for the kill flags just to short-circuit the if statement more quickly?

lib/Target/ARM/ARMLoadStoreOptimizer.cpp
1660 ↗(On Diff #112741)

Extra parens.

If I understand correctly, the original code was checking for the kill flags just to short-circuit the if statement more quickly?

That's what it looks like to me: an attempt to reduce the calls to regsOverlap(). Or at least that would make sense for 'BaseKill'. Checking 'OffKill' I don't get unless 'Base' and 'Off' are somehow known to be related?

MatzeB edited edge metadata.Aug 28 2017, 9:38 AM

If I understand correctly, the original code was checking for the kill flags just to short-circuit the if statement more quickly?

That's what it looks like to me: an attempt to reduce the calls to regsOverlap(). Or at least that would make sense for 'BaseKill'. Checking 'OffKill' I don't get unless 'Base' and 'Off' are somehow known to be related?

Indeed checking for the kill flags is odd and removing the checks looks good to me. However there may be something about the offset register: Won't we have the same problem when the first load overwrites the offset register? So maybe we need to check for an overlap with offsetreg as well (and have a bigger problem if base+offset get overridden?)

If I understand correctly, the original code was checking for the kill flags just to short-circuit the if statement more quickly?

That's what it looks like to me: an attempt to reduce the calls to regsOverlap(). Or at least that would make sense for 'BaseKill'. Checking 'OffKill' I don't get unless 'Base' and 'Off' are somehow known to be related?

Indeed checking for the kill flags is odd and removing the checks looks good to me. However there may be something about the offset register: Won't we have the same problem when the first load overwrites the offset register? So maybe we need to check for an overlap with offsetreg as well (and have a bigger problem if base+offset get overridden?)

This whole OffKill/OffUndef handling is confusing. We only ever query the kill and undef flag and don't even bother to query the register itself. We then pass the kill/undef values to InsertLDR_STR() which doesn't even use the parameter.

Maybe this is because t2LDRDi8 has an immediate offset and hence no offset register is used, while LDRD/STRD always have consecutive even/odd registers so we should always hit the OddRegNum > EvenRegNum && OffImm == 0 case earlier in the function in the cases where an offset register is present.

At least smells to me like OffUndef/OffKill uses could be replaced with assert(!isT2 || MI->getOperand(3).getReg() == 0);

gberry updated this revision to Diff 112932.Aug 28 2017, 11:56 AM

Address review comments

I don't think we ever form an ldrd/strd with a register offset. See ARMPreAllocLoadStoreOpt::CanFormLdStDWord.

MatzeB accepted this revision.Aug 28 2017, 11:59 AM

LGTM

This revision is now accepted and ready to land.Aug 28 2017, 11:59 AM
gberry added a comment.EditedAug 28 2017, 11:59 AM

If I understand correctly, the original code was checking for the kill flags just to short-circuit the if statement more quickly?

That's what it looks like to me: an attempt to reduce the calls to regsOverlap(). Or at least that would make sense for 'BaseKill'. Checking 'OffKill' I don't get unless 'Base' and 'Off' are somehow known to be related?

Indeed checking for the kill flags is odd and removing the checks looks good to me. However there may be something about the offset register: Won't we have the same problem when the first load overwrites the offset register? So maybe we need to check for an overlap with offsetreg as well (and have a bigger problem if base+offset get overridden?)

This whole OffKill/OffUndef handling is confusing. We only ever query the kill and undef flag and don't even bother to query the register itself. We then pass the kill/undef values to InsertLDR_STR() which doesn't even use the parameter.

Maybe this is because t2LDRDi8 has an immediate offset and hence no offset register is used, while LDRD/STRD always have consecutive even/odd registers so we should always hit the OddRegNum > EvenRegNum && OffImm == 0 case earlier in the function in the cases where an offset register is present.

At least smells to me like OffUndef/OffKill uses could be replaced with assert(!isT2 || MI->getOperand(3).getReg() == 0);

Yeah, I came to the same conclusion. I was unable to trigger this assert in any lit or test-suite test, so perhaps we are never using a register offset for this opcode?

This revision was automatically updated to reflect the committed changes.