This is an archive of the discontinued LLVM Phabricator instance.

[ARM64]Fix a bug when lowing shuffle vector to EXT instruction
Needs ReviewPublic

Authored by HaoLiu on Apr 24 2014, 10:18 PM.

Details

Reviewers
t.p.northover
Summary

Hi Tim and other reviewers,

When lowing shuffle vector, there is a function called isEXTMask to check whether we can optimize it into a EXT. But that function misses on situation, as a result it will generate incorrect indexed EXT.
It considers about the mask starts with UNDEFs as following:

<-1, -1, 3, ...> means that an EXT must start at 3 - 2 = 1,

But if there are too many UNDEFs, such as <-1, -1, -1, 1, ...>, the index counter will be overflowed into a very large unsigned int (i.e. unsigned Imm = 1 - 3).

This patch fixes this bug. To make it looks more simpler, it also adjust the position of logic about operands traverse. Review please.

Thanks,
-Hao

Diff Detail

Event Timeline

HaoLiu updated this revision to Diff 8827.Apr 24 2014, 10:18 PM
HaoLiu retitled this revision from to [ARM64]Fix a bug when lowing shuffle vector to EXT instruction.
HaoLiu updated this object.
HaoLiu edited the test plan for this revision. (Show Details)
HaoLiu added a reviewer: t.p.northover.
HaoLiu added a subscriber: Unknown Object (MLST).
t.p.northover edited edge metadata.Apr 25 2014, 3:26 AM

Hi Hao,

This logic looks horribly convoluted, given the problem it's trying to solve. I think it may be time to step back and rewrite it with UNDEF support from the beginning.

One possible idea: the width is going to be a power of 2, so if we made ExpectedElt an APInt of the correct width, any overflow might well do precisely what we *want*. Further, we then ReverseExt if and only if ExpectedElt *starts* in the second half (I think).

So the total logic might be:

FirstRealElt = ...
ExpectedElt = APInt(...);
FirstWrongElt = std::find_if(M.begin(), M.end(), [&](int Elt) { return Elt != ExpectedElt++ && Elt != -1; })
if (FirstWrongElt != M.end()) return false;
// N.b. ExpectedElt is now back to its original value via wrapping
if (ExpectedElt >= NumElts) {
  ReverseExt = true;
  ExpectedElt -= NumElts;
}
Imm = ExpectedElt;
return true;

How does that look?

Cheers.

Tim.

HaoLiu updated this revision to Diff 8881.Apr 27 2014, 11:16 PM
HaoLiu edited edge metadata.

Hi Tim,

Thanks for your suggestion on using APInt and std::find_if. It is very simple and easy to be understood. I've refactored the patch.

BTW, there is a minor issue for this line

"Imm = ExpectedElt;"

It is only true when there is UNDEF in the beginning. If the mask starts from non-undef index, it should be

"Imm = M[0]"

For example, "shuffle V0, V1, <6, 7, 0, 1>" (V0, V1 are vectors of 4 elements), Imm should be "6" not "2".

Thanks,
-Hao

Hi Hao,

BTW, there is a minor issue for this line

"Imm = ExpectedElt;"

It is only true when there is UNDEF in the beginning. If the mask starts from non-undef index, it should be

"Imm = M[0]"

For example, "shuffle V0, V1, <6, 7, 0, 1>" (V0, V1 are vectors of 4 elements), Imm should be "6" not "2".

Ah yes, I see. Well spotted! Actually, doesn't that apply even if M[0]
*is* -1: <-1 7, 0, 1> say? I think I'd been assuming the mask was 2 *
NumElts long for some reason.

So the logic we really want is to count back from *FirstRealElt.
Either of these look like they'd work:

  1. *FirstRealElt - (FirstRealElt - M.begin())
  2. ExpectedElt - NumElts

Cheers.

Tim.

Hi Tim,

Yes. As "(1). *FirstRealElt - (FirstRealElt - M.begin())" may be overflow, this patch implements in "(2). ExpectedElt - NumElts".

I think you mean this patch is OK to be committed. Committed in http://llvm.org/viewvc/llvm-project?view=revision&revision=207485.

Thanks,
-Hao