[InstCombine] Known range pessimizes a pointer advance by narrowing it to i8 + mask
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
Telling clang the true range of a byte makes the code it generates worse. `plain` and `assumed` differ only by a `__builtin_assume` that holds anyway; with it, InstCombine narrows the pointer advance to `i8` and has to mask the result, costing an instruction on x86-64, AArch64 and RISC-V alike. Widening the operand before the arithmetic avoids it. Godbolt: https://godbolt.org/z/GK4Phh8jT
```c
typedef __PTRDIFF_TYPE__ ptrdiff_t;
const signed char *plain(const signed char *p)
{
const signed char op = *p;
return p + (op - 94);
}
const signed char *assumed(const signed char *p)
{
const signed char op = *p;
__builtin_assume(op >= 96);
return p + (op - 94);
}
const signed char *assumed_widened(const signed char *p)
{
const signed char op = *p;
__builtin_assume(op >= 96);
return p + ((ptrdiff_t)op - 94);
}
```
The IR, where `%2` is the loaded `i8`:
```llvm
; plain, assumed_widened
sext i8 %2 to i64 ; resp. zext nneg i8 %2 to i64, then -94 folded into a getelementptr
; assumed
%4 = add nuw i8 %2, 34
%5 = and i8 %4, 63
%6 = zext nneg i8 %5 to i64
```
`op - 94` is `int` arithmetic in the source and the load already materializes the value in a wide register, so narrowing it to `i8` only creates work: the `and` exists solely to make the narrow form correct. Instruction counts, clang 23 (trunk) at `-O2`, same on clang 21:
| | x86-64 | AArch64 | rv64im |
| --- | --- | --- | --- |
| `plain` | 4 | 4 | 4 |
| `assumed` | 5 | 5 | 5 |
| `assumed_widened` | 4 | 4 | 4 |
The same thing happens without `__builtin_assume` when a dominating comparison supplies the range, which is how I ran into it: a loop with an `if (op < 91) { ++p; continue; }` guard ahead of `p += op - 94`. There the masked advance is no longer a constant on the short path, so it also costs the loop its private increment.
Contributor guide
Assessment
This issue has not been assessed yet.