| Issue |
107774
|
| Summary |
`assume`s prevent deletion of dead code
|
| Labels |
missed-optimization
|
| Assignees |
|
| Reporter |
Kmeakin
|
# Rust example
`src` contains dead branches that are not removed:
https://godbolt.org/z/MabExKqET
```rust
#[no_mangle]
pub fn src(s: &str) -> bool {
s.chars().next().is_none()
}
#[no_mangle]
pub fn tgt(s: &str) -> bool {
s.len() == 0
}
```
```asm
src:
cbz x1, .LBB0_2
ldrsb w8, [x0]
tbnz w8, #31, .LBB0_3
.LBB0_2:
cmp x1, #0
cset w0, eq
ret
.LBB0_3:
and w8, w8, #0xff
cmp w8, #224
cmp x1, #0
cset w0, eq
ret
tgt:
cmp x1, #0
cset w0, eq
ret
```
# C example
The same example, translated to C
https://godbolt.org/z/Yn3Esa37M
```c
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
typedef uint8_t u8;
typedef uint32_t u32;
typedef size_t usize;
#if ASSUME == 1
#define assume(cond) __builtin_assume(cond)
#else
#define assume(cond) (cond)
#endif
const u32 NONE = -1;
inline u32 next_codepoint(u8* bytes, usize len) {
if (len == 0) {
return NONE;
}
assume(len != 0);
u8 b0 = bytes[0];
if (b0 < 0x80) {
return b0;
}
assume(len != 1);
u8 b1 = bytes[1];
u32 b0_b1 = (b0 & 0x1F) << 6 | (b1 & 0x3F);
if (b0 < 0xE0) {
return b0_b1;
}
assume(len != 2);
u8 b2 = bytes[2];
u32 b0_b1_b2 = (b0_b1 << 6) | (b2 & 0x3F);
if (b0 < 0xF0) {
return b0_b1_b2;
}
assume(len != 3);
u8 b3 = bytes[3];
u32 b0_b1_b2_b3 = (b0_b1_b2 << 6) | (b3 & 0x3F);
return b0_b1_b2_b3 & 0x1F'FF'FF;
}
bool src(u8* bytes, usize len) { return next_codepoint(bytes, len) == NONE; }
bool tgt(u8* bytes, usize len) { return len == 0; }
```
If `assume` is defined as a no-op instead as `__builtin_assume`, the dead code is able to be deleted.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs