llvm / llvm/llvm-project

[InstCombine] Missed fold: xor(zext(or disjoint X, C1), C2) -> xor(zext(X), C2 ^ zext(C1))

Open
#214,652 0 comments 0 reactions 1 assignee Claimed by @hunterhhunter View on GitHub
llvm:instcombine miscompilation
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

InstCombine does not currently fold the following pattern:

```llvm
define i64 @src(i32 %x) {
%or = or disjoint i32 %x, 1
%z = zext i32 %or to i64
%r = xor i64 %z, 2611923443488327891
ret i64 %r
}
```

into:

```llvm
define i64 @tgt(i32 %x) {
%z = zext i32 %x to i64
%r = xor i64 %z, 2611923443488327890
ret i64 %r
}
```

`or disjoint` guarantees that `X` and `C1` have no overlapping set bits, so
`X | C1` is equivalent to `X ^ C1`. Therefore, the constant introduced by the
inner `or` can be absorbed into the outer XOR after zero-extension:

```text
xor(zext(or disjoint X, C1), C2)
-> xor(zext(X), C2 ^ zext(C1))
```

This removes the intermediate `or`, reducing the IR sequence from three
instructions to two. The primary benefit of this fold is IR simplification
and canonicalization.

## Verification

Current LLVM trunk:
https://godbolt.org/z/M75jvGerP

Alive2:
https://alive2.llvm.org/ce/z/zsnvLo

## Codegen comparison

Compiler Explorer:
https://compiler-explorer.com/z/MhKsdnMoz

cc @ParkHanbum

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.