[InstCombine] Fix miscompile on GEP+load to icmp fold (PR45210)
authorHyeongyu Kim <gusrb406@snu.ac.kr>
Mon, 31 May 2021 05:05:29 +0000 (14:05 +0900)
committerJuneyoung Lee <aqjune@gmail.com>
Mon, 31 May 2021 05:08:20 +0000 (14:08 +0900)
commit4f2fd3818b0eb26806f366bc37369349aeedcaf9
tree73b42a25c0768738cdc340a54454ad4c6ab217dc
parent22668c6e1f36b375944a00495d71e20ee15639fb
[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