[InstCombine] Fix miscompile on GEP+load to icmp fold (PR45210)
authorhyeongyukim <gusrb406@snu.ac.kr>
Thu, 17 Jun 2021 10:28:24 +0000 (19:28 +0900)
committerJuneyoung Lee <aqjune@gmail.com>
Thu, 17 Jun 2021 10:46:17 +0000 (19:46 +0900)
commit69b0ed9a0a6aeab0b1c93d0a76c66a63c1d6f410
treee160c5d9193b6fd802659ad5ce58f641d55055bd
parent1a4af2e45ee59cff3d577986b9b7f3f5bd5ab01f
[InstCombine] Fix miscompile on GEP+load to icmp fold (PR45210)

As noted in PR45210: https://bugs.llvm.org/show_bug.cgi?id=45210
...the bug is triggered as Eli say when sext(idx) * ElementSize overflows.

```
   // assume that GV is an array of 4-byte elements
   GEP = gep GV, 0, Idx // this is accessing Idx * 4
   L = load GEP
   ICI = icmp eq L, value
 =>
   ICI = icmp eq Idx, NewIdx
```

The foldCmpLoadFromIndexedGlobal function simplifies GEP+load operation to icmp.
And there is a problem because Idx * ElementSize can overflow.

Let's assume that the wanted value is at offset 0.
Then, there are actually four possible values for Idx to match offset 0: 0x00..00, 0x40..00, 0x80..00, 0xC0..00.
We should return true for all these values, but currently, the new icmp only returns true for 0x00..00.

This problem can be solved by masking off (trailing zeros of ElementSize) bits from Idx.

```
   ...
 =>
   Idx' = and Idx, 0x3F..FF
   ICI = icmp eq Idx', NewIdx
```

Reviewed By: efriedma

Differential Revision: https://reviews.llvm.org/D99481
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
llvm/test/Transforms/InstCombine/load-cmp.ll